@yielded/agent 0.1.0-beta.173 → 0.1.0-beta.175

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 (266) hide show
  1. package/dist/{Admin-BX9ns28E.d.mts → Admin-Qa3I1oA5.d.mts} +61 -21
  2. package/dist/{Agent-9aBoIi74.d.mts → Agent-B39jRnFv.d.mts} +2 -2
  3. package/dist/{Agent-0WvBWWbM.mjs → Agent-BiRbr73L.mjs} +7 -6
  4. package/dist/Agent-BiRbr73L.mjs.map +1 -0
  5. package/dist/{AgentRuntime-BfP14534.d.mts → AgentRuntime-CHDyRbSf.d.mts} +12 -12
  6. package/dist/{AgentRuntime-CQ-qcETl.mjs → AgentRuntime-DaDKMasp.mjs} +290 -273
  7. package/dist/AgentRuntime-DaDKMasp.mjs.map +1 -0
  8. package/dist/{Digest-DCuPlhNk.mjs → Digest-C3EODOee.mjs} +42 -15
  9. package/dist/Digest-C3EODOee.mjs.map +1 -0
  10. package/dist/{DurableAgentRuntime-BAmSkWYr.mjs → DurableAgentRuntime-CPlw5_7e.mjs} +1557 -1458
  11. package/dist/DurableAgentRuntime-CPlw5_7e.mjs.map +1 -0
  12. package/dist/{EventSource-BwliwQz9.d.mts → EventSource-BTu68yDW.d.mts} +2 -2
  13. package/dist/InMemory.d.mts +2 -2
  14. package/dist/{MessageDelivery-B943ebI_.d.mts → MessageDelivery-DjAZJ4Fd.d.mts} +42 -42
  15. package/dist/{Messaging-C_6OOg_s.d.mts → Messaging-SVu6rWV8.d.mts} +12 -6
  16. package/dist/{MessagingHost-B8oKM7AC.d.mts → MessagingHost-C6SOAcoG.d.mts} +2 -2
  17. package/dist/{MessagingHost-CRUK4JBi.mjs → MessagingHost-CZCyrnvJ.mjs} +27 -26
  18. package/dist/MessagingHost-CZCyrnvJ.mjs.map +1 -0
  19. package/dist/{Output-Dsx6k52t.d.mts → Output-CRamN1Fy.d.mts} +2 -2
  20. package/dist/{PreparedInputAdmission-CxSJSiTl.d.mts → PreparedInputAdmission-wgY4JMZY.d.mts} +3 -3
  21. package/dist/{Records-BiuJDWNe.mjs → Records-DzL4Kbtw.mjs} +2 -2
  22. package/dist/{Records-BiuJDWNe.mjs.map → Records-DzL4Kbtw.mjs.map} +1 -1
  23. package/dist/{RunContinuation-FHM7XPjq.d.mts → RunContinuation-3jB5pULC.d.mts} +13 -7
  24. package/dist/{RunContinuation-DHYNAQFi.mjs → RunContinuation-BiyKJK32.mjs} +173 -82
  25. package/dist/RunContinuation-BiyKJK32.mjs.map +1 -0
  26. package/dist/{RunJournal-kfKVxJj7.mjs → RunJournal-CPMKcfd0.mjs} +106 -73
  27. package/dist/RunJournal-CPMKcfd0.mjs.map +1 -0
  28. package/dist/{RunOptions-D8zxFIrZ.d.mts → RunOptions-Be77lKVZ.d.mts} +2 -2
  29. package/dist/{RunStorage-uqPxps09.mjs → RunStorage-CzutHJBE.mjs} +10 -6
  30. package/dist/RunStorage-CzutHJBE.mjs.map +1 -0
  31. package/dist/{Scheduling-CVyfXlBR.mjs → Scheduling-07_dsGED.mjs} +12 -12
  32. package/dist/Scheduling-07_dsGED.mjs.map +1 -0
  33. package/dist/{Subagent-vpffemql.mjs → Subagent-CexndZSp.mjs} +53 -40
  34. package/dist/Subagent-CexndZSp.mjs.map +1 -0
  35. package/dist/{Subagent-E6tvd7-k.d.mts → Subagent-xhN_aD1r.d.mts} +20 -9
  36. package/dist/{SubagentHost-B6w2m-SI.d.mts → SubagentHost-D1xBgn9g.d.mts} +2 -2
  37. package/dist/{Subscription-DONig54Q.d.mts → Subscription-DmIHlOJK.d.mts} +2 -2
  38. package/dist/{SubscriptionInput-mJIRxWJM.d.mts → SubscriptionInput-DgcQhvbe.d.mts} +2 -2
  39. package/dist/{Thread-dk-QiNml.d.mts → Thread-DzdJAY4J.d.mts} +4 -3
  40. package/dist/{ThreadHistory-ByxS8HU1.d.mts → ThreadHistory-KPPBJLJb.d.mts} +12 -2
  41. package/dist/{ThreadImport-DckUMEqJ.mjs → ThreadImport-CjlG57vH.mjs} +9 -9
  42. package/dist/ThreadImport-CjlG57vH.mjs.map +1 -0
  43. package/dist/{ThreadImport-DpHxjBrA.d.mts → ThreadImport-DP-vOk2F.d.mts} +5 -5
  44. package/dist/{ThreadStore-CEekRa80.mjs → ThreadStore-EuUilthA.mjs} +162 -85
  45. package/dist/ThreadStore-EuUilthA.mjs.map +1 -0
  46. package/dist/{ThreadTransfer-B4gTQLIl.mjs → ThreadTransfer-DB_zsrtJ.mjs} +4 -4
  47. package/dist/{ThreadTransfer-B4gTQLIl.mjs.map → ThreadTransfer-DB_zsrtJ.mjs.map} +1 -1
  48. package/dist/{WorkerAdmission-DFVbbVh2.mjs → WorkerAdmission-eBeXt_mu.mjs} +5 -5
  49. package/dist/{WorkerAdmission-DFVbbVh2.mjs.map → WorkerAdmission-eBeXt_mu.mjs.map} +1 -1
  50. package/dist/{agent-registration-ByMZ_cK5.mjs → agent-registration-a6QYaG3h.mjs} +70 -57
  51. package/dist/agent-registration-a6QYaG3h.mjs.map +1 -0
  52. package/dist/capabilities/Approval.mjs +2 -2
  53. package/dist/capabilities/Approval.mjs.map +1 -1
  54. package/dist/capabilities/BrowserUse.d.mts +102 -1867
  55. package/dist/capabilities/BrowserUse.mjs +74 -798
  56. package/dist/capabilities/BrowserUse.mjs.map +1 -1
  57. package/dist/capabilities/Budget.mjs +3 -1
  58. package/dist/capabilities/Budget.mjs.map +1 -1
  59. package/dist/capabilities/CodeMode.d.mts +1 -1
  60. package/dist/capabilities/CodeMode.mjs +16 -9
  61. package/dist/capabilities/CodeMode.mjs.map +1 -1
  62. package/dist/capabilities/Commands.d.mts +1 -1
  63. package/dist/capabilities/McpClient.mjs +1 -1
  64. package/dist/capabilities/McpClient.mjs.map +1 -1
  65. package/dist/capabilities/Messaging.d.mts +1 -1
  66. package/dist/capabilities/Messaging.mjs +5 -5
  67. package/dist/capabilities/Messaging.mjs.map +1 -1
  68. package/dist/capabilities/ModelContext.d.mts +1 -1
  69. package/dist/capabilities/ModelContext.mjs +7 -5
  70. package/dist/capabilities/ModelContext.mjs.map +1 -1
  71. package/dist/capabilities/Redaction.mjs +49 -19
  72. package/dist/capabilities/Redaction.mjs.map +1 -1
  73. package/dist/capabilities/RunHooks.d.mts +2 -2
  74. package/dist/capabilities/RunHooks.mjs +1 -1
  75. package/dist/capabilities/RunHooks.mjs.map +1 -1
  76. package/dist/capabilities/Subagent.d.mts +1 -1
  77. package/dist/capabilities/Subagent.mjs +1 -1
  78. package/dist/capabilities/SubagentReservations.mjs +3 -1
  79. package/dist/capabilities/SubagentReservations.mjs.map +1 -1
  80. package/dist/capabilities/WebCapture.mjs.map +1 -1
  81. package/dist/capabilities/WebSearch.mjs +7 -7
  82. package/dist/capabilities/WebSearch.mjs.map +1 -1
  83. package/dist/core/Agent.d.mts +1 -1
  84. package/dist/core/Agent.mjs +1 -1
  85. package/dist/core/AgentUpdates.mjs +8 -8
  86. package/dist/core/AgentUpdates.mjs.map +1 -1
  87. package/dist/core/Thread.d.mts +2 -2
  88. package/dist/core/Thread.mjs +6 -4
  89. package/dist/core/Thread.mjs.map +1 -1
  90. package/dist/core/Usage.mjs +2 -2
  91. package/dist/core/Usage.mjs.map +1 -1
  92. package/dist/durable/ActivityStore.mjs +1 -1
  93. package/dist/durable/Admin.d.mts +1 -1
  94. package/dist/durable/Admin.mjs +1 -1
  95. package/dist/durable/AgentRegistration.d.mts +1 -1
  96. package/dist/durable/AgentRegistration.mjs +1 -1
  97. package/dist/durable/Certification.d.mts +1 -1
  98. package/dist/durable/CommittedActivity.d.mts +1 -1
  99. package/dist/durable/CommittedActivity.mjs +3 -3
  100. package/dist/durable/Digest.mjs +1 -1
  101. package/dist/durable/DurableAgentRuntime.d.mts +1 -1
  102. package/dist/durable/DurableAgentRuntime.mjs +2 -2
  103. package/dist/durable/EventSource.d.mts +1 -1
  104. package/dist/durable/EventSource.mjs +7 -7
  105. package/dist/durable/EventSource.mjs.map +1 -1
  106. package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
  107. package/dist/durable/LifecyclePublication.d.mts +1 -1
  108. package/dist/durable/LifecyclePublication.mjs +2 -2
  109. package/dist/durable/MessageDelivery.d.mts +1 -1
  110. package/dist/durable/MessageDelivery.mjs +2 -2
  111. package/dist/durable/MessageDeliveryStoreConformance.d.mts +40 -40
  112. package/dist/durable/MessageDeliveryStoreConformance.mjs +2 -2
  113. package/dist/durable/PersistentHistory.d.mts +2 -2
  114. package/dist/durable/PersistentHistory.mjs +4 -4
  115. package/dist/durable/PreparedInputAdmission.d.mts +1 -1
  116. package/dist/durable/RecordFormat.mjs +3 -3
  117. package/dist/durable/RecordFormat.mjs.map +1 -1
  118. package/dist/durable/Records.mjs +1 -1
  119. package/dist/durable/Recovery.d.mts +1 -1
  120. package/dist/durable/Recovery.mjs +1 -1
  121. package/dist/durable/RunContinuation.d.mts +2 -2
  122. package/dist/durable/RunContinuation.mjs +3 -3
  123. package/dist/durable/RunJournal.d.mts +2 -2
  124. package/dist/durable/RunJournal.mjs +2 -2
  125. package/dist/durable/RunStorage.d.mts +1 -1
  126. package/dist/durable/RunStorage.mjs +1 -1
  127. package/dist/durable/Schedule.mjs +1 -1
  128. package/dist/durable/ScheduleStoreConformance.mjs +1 -1
  129. package/dist/durable/ScheduleTransition.mjs +1 -1
  130. package/dist/durable/Scheduling.d.mts +1 -1
  131. package/dist/durable/Scheduling.mjs +1 -1
  132. package/dist/durable/SettlementPublisher.d.mts +1 -1
  133. package/dist/durable/SettlementPublisher.mjs +3 -3
  134. package/dist/durable/SqlMemoryStore.mjs +5 -3
  135. package/dist/durable/SqlMemoryStore.mjs.map +1 -1
  136. package/dist/durable/SubmissionLedger.d.mts +1 -1
  137. package/dist/durable/SubmissionLedger.mjs +11 -3
  138. package/dist/durable/SubmissionLedger.mjs.map +1 -1
  139. package/dist/durable/SubmissionLedgerConformance.d.mts +1 -1
  140. package/dist/durable/SubmissionLedgerConformance.mjs +6 -6
  141. package/dist/durable/SubmissionStatus.d.mts +1 -1
  142. package/dist/durable/Subscription.d.mts +1 -1
  143. package/dist/durable/Subscription.mjs +2 -2
  144. package/dist/durable/SubscriptionInput.d.mts +1 -1
  145. package/dist/durable/SubscriptionInput.mjs +4 -4
  146. package/dist/durable/SubscriptionInput.mjs.map +1 -1
  147. package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
  148. package/dist/durable/SubscriptionStoreConformance.mjs +3 -3
  149. package/dist/durable/SubscriptionStoreConformance.mjs.map +1 -1
  150. package/dist/durable/SubscriptionTools.d.mts +2 -2
  151. package/dist/durable/SubscriptionTransition.d.mts +1 -1
  152. package/dist/durable/SubscriptionTransition.mjs +1 -1
  153. package/dist/durable/Subscriptions.d.mts +5 -5
  154. package/dist/durable/Subscriptions.mjs +3 -3
  155. package/dist/durable/Subscriptions.mjs.map +1 -1
  156. package/dist/durable/ThreadArchiveRange.d.mts +1 -1
  157. package/dist/durable/ThreadArchiveRange.mjs +1 -1
  158. package/dist/durable/ThreadContextHistory.d.mts +1 -1
  159. package/dist/durable/ThreadContextHistory.mjs +2 -2
  160. package/dist/durable/ThreadContextHistoryProjection.mjs +1 -1
  161. package/dist/durable/ThreadImport.d.mts +1 -1
  162. package/dist/durable/ThreadImport.mjs +1 -1
  163. package/dist/durable/ThreadInvariants.d.mts +3 -3
  164. package/dist/durable/ThreadInvariants.mjs +5 -5
  165. package/dist/durable/ThreadInvariants.mjs.map +1 -1
  166. package/dist/durable/ThreadProjection.mjs +1 -1
  167. package/dist/durable/ThreadProjectionMaintenance.d.mts +1 -1
  168. package/dist/durable/ThreadReader.d.mts +1 -1
  169. package/dist/durable/ThreadReader.mjs +1 -1
  170. package/dist/durable/ThreadStore.d.mts +1 -1
  171. package/dist/durable/ThreadStore.mjs +2 -2
  172. package/dist/durable/ThreadStoreConformance.d.mts +1 -1
  173. package/dist/durable/ThreadStoreConformance.mjs +4 -4
  174. package/dist/durable/ThreadTransfer.d.mts +1 -1
  175. package/dist/durable/ThreadTransfer.mjs +1 -1
  176. package/dist/durable/ThreadWork.d.mts +2 -2
  177. package/dist/durable/ThreadWork.mjs +12 -6
  178. package/dist/durable/ThreadWork.mjs.map +1 -1
  179. package/dist/durable/ToolReconciler.mjs +1 -1
  180. package/dist/durable/WakeScheduler.mjs +23 -39
  181. package/dist/durable/WakeScheduler.mjs.map +1 -1
  182. package/dist/durable/WorkerAdmission.d.mts +1 -1
  183. package/dist/durable/WorkerAdmission.mjs +1 -1
  184. package/dist/durable/WorkerHost.d.mts +2 -2
  185. package/dist/engine/AgentRuntime.d.mts +1 -1
  186. package/dist/engine/AgentRuntime.mjs +1 -1
  187. package/dist/engine/MessagingHost.d.mts +1 -1
  188. package/dist/engine/MessagingHost.mjs +1 -1
  189. package/dist/engine/Output.d.mts +1 -1
  190. package/dist/engine/Output.mjs +1 -1
  191. package/dist/engine/RunOptions.d.mts +1 -1
  192. package/dist/engine/SubagentHost.d.mts +1 -1
  193. package/dist/engine/ThreadHistory.d.mts +1 -1
  194. package/dist/engine/ThreadHistory.mjs +3 -2
  195. package/dist/engine/ThreadHistory.mjs.map +1 -1
  196. package/dist/index.d.mts +21 -21
  197. package/dist/index.mjs +16 -16
  198. package/dist/{output-contract-CMIhu4Cw.mjs → output-contract-DCnLYCdp.mjs} +12 -15
  199. package/dist/{output-contract-CMIhu4Cw.mjs.map → output-contract-DCnLYCdp.mjs.map} +1 -1
  200. package/dist/{run-context-reader-OcsZr4bk.d.mts → run-context-reader-DVhJZ1Qe.d.mts} +2 -2
  201. package/package.json +1 -1
  202. package/src/capabilities/Approval.ts +58 -60
  203. package/src/capabilities/BrowserUse.ts +89 -944
  204. package/src/capabilities/Budget.ts +8 -1
  205. package/src/capabilities/CodeMode.ts +57 -33
  206. package/src/capabilities/McpClient.ts +2 -2
  207. package/src/capabilities/Messaging.ts +51 -55
  208. package/src/capabilities/ModelContext.ts +5 -2
  209. package/src/capabilities/Redaction.ts +64 -34
  210. package/src/capabilities/RunHooks.ts +52 -55
  211. package/src/capabilities/Subagent.ts +33 -33
  212. package/src/capabilities/SubagentReservations.ts +9 -1
  213. package/src/capabilities/WebCapture.ts +6 -0
  214. package/src/capabilities/WebSearch.ts +10 -7
  215. package/src/capabilities/internal/subagent-background.ts +202 -158
  216. package/src/core/Agent.ts +11 -6
  217. package/src/core/AgentUpdates.ts +8 -8
  218. package/src/core/Thread.ts +142 -146
  219. package/src/core/Usage.ts +7 -8
  220. package/src/core/internal/agent-updates.ts +1 -0
  221. package/src/durable/DurableAgentRuntime.ts +1024 -829
  222. package/src/durable/EventSource.ts +15 -9
  223. package/src/durable/RecordFormat.ts +5 -3
  224. package/src/durable/RunContinuation.ts +316 -113
  225. package/src/durable/RunJournal.ts +106 -114
  226. package/src/durable/RunStorage.ts +129 -124
  227. package/src/durable/Scheduling.ts +639 -651
  228. package/src/durable/SqlMemoryStore.ts +8 -6
  229. package/src/durable/SubmissionLedger.ts +11 -0
  230. package/src/durable/SubscriptionInput.ts +5 -3
  231. package/src/durable/SubscriptionStoreConformance.ts +23 -23
  232. package/src/durable/Subscriptions.ts +18 -19
  233. package/src/durable/ThreadImport.ts +18 -19
  234. package/src/durable/ThreadInvariants.ts +2 -1
  235. package/src/durable/ThreadStore.ts +217 -111
  236. package/src/durable/ThreadWork.ts +11 -2
  237. package/src/durable/WakeScheduler.ts +34 -66
  238. package/src/durable/internal/StorageOwner.ts +10 -4
  239. package/src/durable/internal/agent-registration.ts +96 -89
  240. package/src/durable/internal/canonical-json.ts +61 -20
  241. package/src/durable/internal/prompt-history-cache.ts +13 -4
  242. package/src/durable/internal/record-encoding.ts +120 -64
  243. package/src/durable/internal/schedule-time.ts +6 -6
  244. package/src/durable/internal/usage-totals.ts +35 -0
  245. package/src/durable/internal/worker-host.ts +69 -74
  246. package/src/engine/MessagingHost.ts +4 -2
  247. package/src/engine/ThreadHistory.ts +47 -48
  248. package/src/engine/internal/agent-runtime.ts +1298 -1217
  249. package/src/engine/internal/output-contract.ts +15 -15
  250. package/src/engine/internal/primitive-delta.ts +2 -3
  251. package/src/engine/internal/provisional-text.ts +12 -10
  252. package/src/engine/internal/tool-exposure.ts +22 -18
  253. package/src/engine/internal/tool-telemetry.ts +15 -12
  254. package/dist/Agent-0WvBWWbM.mjs.map +0 -1
  255. package/dist/AgentRuntime-CQ-qcETl.mjs.map +0 -1
  256. package/dist/Digest-DCuPlhNk.mjs.map +0 -1
  257. package/dist/DurableAgentRuntime-BAmSkWYr.mjs.map +0 -1
  258. package/dist/MessagingHost-CRUK4JBi.mjs.map +0 -1
  259. package/dist/RunContinuation-DHYNAQFi.mjs.map +0 -1
  260. package/dist/RunJournal-kfKVxJj7.mjs.map +0 -1
  261. package/dist/RunStorage-uqPxps09.mjs.map +0 -1
  262. package/dist/Scheduling-CVyfXlBR.mjs.map +0 -1
  263. package/dist/Subagent-vpffemql.mjs.map +0 -1
  264. package/dist/ThreadImport-DckUMEqJ.mjs.map +0 -1
  265. package/dist/ThreadStore-CEekRa80.mjs.map +0 -1
  266. package/dist/agent-registration-ByMZ_cK5.mjs.map +0 -1
@@ -12,37 +12,38 @@ import { DelegationDepth, SubagentBudgetReservation, SubagentDelegationCaps, Sub
12
12
  import { o as Selection, s as Snapshot } from "./ToolExposure-hTJT2ekj.mjs";
13
13
  import { ChildRunUsage, InputTokenUsage, ModelCallUsage, ModelResponseIdentity, ModelUsageGroup, OutputTokenUsage, RunUsageReport, RunUsageSummary, emptyRunTotals, runTotalsFromSummary, sumRunTotals, summarizeModelUsage, unknownRunTotals } from "./core/Usage.mjs";
14
14
  import { C as MessageStatus, S as MessageRef, _ as WorkerStop, b as WorkerUpdate, c as WorkerError, f as WorkerRef, l as WorkerHistoryEntry, o as WorkerCompletion, r as FrameworkMessage } from "./Worker-DZjdMjZn.mjs";
15
- import { a as PeerMessageCapacity, d as MessageAdmission, f as MessagingError, i as PeerDeliveryLifetime, o as PeerRoutes, p as PeerName, r as PeerAuthorizer, t as MessagingHost } from "./MessagingHost-CRUK4JBi.mjs";
15
+ import { a as PeerMessageCapacity, d as MessageAdmission, f as MessagingError, i as PeerDeliveryLifetime, o as PeerRoutes, p as PeerName, r as PeerAuthorizer, t as MessagingHost } from "./MessagingHost-CZCyrnvJ.mjs";
16
16
  import { SubagentHost } from "./engine/SubagentHost.mjs";
17
+ import { Store, makeMemoryStore } from "./core/Thread.mjs";
17
18
  import { ThreadHistory } from "./engine/ThreadHistory.mjs";
18
19
  import { n as RunToolVisibility } from "./ToolExposure-DBATXxmL.mjs";
19
- import { C as boundedValueFootprint, n as AgentChildPending, p as renderInputPrompt, u as executeWithUsageAccountingUnknown } from "./AgentRuntime-CQ-qcETl.mjs";
20
+ import { C as boundedValueFootprint, n as AgentChildPending, p as renderInputPrompt, u as executeWithUsageAccountingUnknown } from "./AgentRuntime-DaDKMasp.mjs";
20
21
  import { ContextRolloverTool } from "./engine/ContextWindow.mjs";
21
22
  import { getToolExecutionClass } from "./engine/DurableStep.mjs";
22
23
  import { CompactionError, ContextCompactor } from "./engine/ContextCompactor.mjs";
23
24
  import { AgentUpdateAcceptance, CurrentToolFailureObserver, ModelUsageAccounting, RunContextPreparation, RunContextPreparationPassthrough, RunToolAuthorization, RunToolScheduling } from "./engine/RunOptions.mjs";
24
- import { A as MAX_RUN_EVIDENCE_RECORDS, At as WorkHandoffCompleted, Bt as WorkerReportingIntent, Ct as ToolCallResolved, Dt as ToolStepSettled, Et as ToolOperation, Ft as WorkerInputRequested, G as PromptRecord, H as PeerMessagePrepared, I as ModelCallAborted, It as WorkerOrigin, Mt as WorkerContinuation, Nt as WorkerInputCompleted, O as MAX_RUN_CONTINUATION_BYTES, Ot as ToolUnavailable, P as MAX_RUN_TOOL_CALL_IDENTITIES, Pt as WorkerInputRefused, R as ModelResponseInterrupted, Rt as WorkerReportPrepared, Tt as ToolCallUnknown, U as PersistedJson, V as PROMPT_EVIDENCE_TAGS, Vt as WorkerStopRequested, X as RecordEnvelope, Z as RecordId, _t as SubmissionSettledRecord, at as RunDurationExhausted, bt as ToolApprovalDecided, c as CanonicalBatch, et as RepairAnnotated, f as CanonicalSequence, ft as SubagentJoined, g as DeclaredToolCall, gt as SubmissionSettled, ht as SubagentStarted, i as BatchId, jt as WorkerAdmission, kt as UserInputRecorded, lt as RunStartedRecord, mt as SubagentRequested, n as AgentUpdateEmitted, o as CURRENT_RECORD_FORMAT, p as CompactionCreated, pt as SubagentLineageRecorded, rt as RunContextRecorded, st as RunPolicyUsageReserved, t as AbortRequested, ut as SettlementFailureDiagnostic, v as DefinitionDigests, vt as SubtreeBudgetReserved, w as MAX_PERSISTED_JSON_BYTES, wt as ToolCallSettled, xt as ToolApprovalRequested, zt as WorkerReportRefused } from "./Records-BiuJDWNe.mjs";
25
- import { i as digestCanonicalJson, r as canonicalJson, s as digestJson } from "./Digest-DCuPlhNk.mjs";
25
+ import { A as MAX_RUN_EVIDENCE_RECORDS, At as WorkHandoffCompleted, Bt as WorkerReportingIntent, Ct as ToolCallResolved, Dt as ToolStepSettled, Et as ToolOperation, Ft as WorkerInputRequested, G as PromptRecord, H as PeerMessagePrepared, I as ModelCallAborted, It as WorkerOrigin, Mt as WorkerContinuation, Nt as WorkerInputCompleted, O as MAX_RUN_CONTINUATION_BYTES, Ot as ToolUnavailable, P as MAX_RUN_TOOL_CALL_IDENTITIES, Pt as WorkerInputRefused, R as ModelResponseInterrupted, Rt as WorkerReportPrepared, Tt as ToolCallUnknown, U as PersistedJson, V as PROMPT_EVIDENCE_TAGS, Vt as WorkerStopRequested, X as RecordEnvelope, Z as RecordId, _t as SubmissionSettledRecord, at as RunDurationExhausted, bt as ToolApprovalDecided, c as CanonicalBatch, et as RepairAnnotated, f as CanonicalSequence, ft as SubagentJoined, g as DeclaredToolCall, gt as SubmissionSettled, ht as SubagentStarted, i as BatchId, jt as WorkerAdmission, kt as UserInputRecorded, lt as RunStartedRecord, mt as SubagentRequested, n as AgentUpdateEmitted, o as CURRENT_RECORD_FORMAT, p as CompactionCreated, pt as SubagentLineageRecorded, rt as RunContextRecorded, st as RunPolicyUsageReserved, t as AbortRequested, ut as SettlementFailureDiagnostic, v as DefinitionDigests, vt as SubtreeBudgetReserved, w as MAX_PERSISTED_JSON_BYTES, wt as ToolCallSettled, xt as ToolApprovalRequested, zt as WorkerReportRefused } from "./Records-DzL4Kbtw.mjs";
26
+ import { i as digestCanonicalJson, r as canonicalJson, s as digestJson } from "./Digest-C3EODOee.mjs";
26
27
  import { AbortCommand, AbortIntentRequest, AdmissionPolicyError, AdmissionRequest, ApprovalDecisionCommand, ApprovalPendingSuspension, BeginChildBudgetReleaseRequest, ChildReservationId, ChildSettledNotification, ClaimHandoff, ClaimRequest, FundingOwnerRequest, LedgerError, MarkReadyRequest, MarkUnknownRequest, ParentLinkage, RecoverySnapshotRequest, ReleaseChildBudgetRequest, RevertJoiningRequest, Settlement, SettlementFinalization, SubmissionLedger, SubmissionLookupById, SubmissionLookupByKey, SubmissionScheduling, UnknownResolutionCommand, WaitingChild, WaitingForChildSuspension, WorkerLedgerState, submissionAbortBatchId, submissionAbortRecordId, submissionInputBatchId, submissionInputRecordId, submissionSettlementBatchId, submissionSettlementId, submissionSettlementRecordId, unknownResolutionKind } from "./durable/SubmissionLedger.mjs";
27
28
  import { DeclaredPendingBatchEvidence, OpenDelegationCallEvidence, OpenToolCallEvidence, PendingApprovalEvidence, RecoveryDecision, RecoveryEvidence, classifyRecovery, pendingApprovalForRecovery } from "./durable/Recovery.mjs";
28
29
  import { ExplainedEvidence, ExplainedSubmission, ExplainedUnknownCall, ObligationEntry, ObligationReport, RecoveryExplanation, RetryRefused, obligationSeverityOf, predictRecoveryDisposition, recoveryDecisionMeaning } from "./durable/Admin.mjs";
29
- import { a as compileRegistrations, c as resolveDefinitionBinding, l as resolveWorkerBinding, n as CurrentBindingSelection, o as definitionDigestsEqual, s as makeLegacyWorkerBinding, t as BindingUnavailable, u as toolReplayContracts } from "./agent-registration-ByMZ_cK5.mjs";
30
- import { A as subagentStartedBatchId, B as turnApprovalsBatchId, C as runStartedRecordId, D as subagentLineageRecordId, E as subagentLineageBatchId, F as toolCallResolvedRecordId, G as turnResponseBatchId, H as turnCanonicalBatch, I as toolCallResultBatchId, J as workerInputRecordId, K as turnResultsBatch, L as toolCallUnknownRecordId, M as toolApprovalDecisionRecordId, N as toolApprovalRequestRecordId, O as subagentRequestedBatchId, P as toolCallResolutionBatchId, Q as toolCallSettledRecordId, R as toolStepSettledBatchId, S as runStartedBatchId, T as subagentJoinedRecordId, U as turnIdForRun, W as turnResponseBatch, X as workerReportRecordId, Y as workerOriginRecordId, Z as makeJournalMetadata, a as childIdempotencyKeyFor, b as runDurationRecordId, c as compactionRecordId, d as modelResponseInterruptedBatchId, f as modelResponseInterruptedRecordId, g as projectRunJournalStream, i as approvalDecisionBatchId, j as subagentStartedRecordId, k as subagentRequestedRecordId, l as firstWorkerInputRecordId, m as peerMessageRecordId, o as childThreadIdFor, p as modelResponseRecordId, r as agentUpdateRecordId, s as compactionBatchId, t as RunJournalError, u as markUnknownBatchId, v as runCompletedRecordId, w as subagentJoinBatchId, x as runIdForSubmission, y as runDurationBatchId, z as toolStepSettledRecordId } from "./RunJournal-kfKVxJj7.mjs";
31
- import { $ as ThreadTailRequest, B as ThreadPromptRead, F as ThreadIdentityRequest, I as ThreadMaterialization, J as ThreadStore, R as ThreadObservation, U as ThreadReader, V as ThreadRead, X as ThreadStoreError, Y as ThreadStoreDiagnostic, _t as isPreContinuationFact, bt as terminalUsageCharge, gt as executionRunIds, ht as canonicalRunIds, lt as readWorkerState, n as AppendRequest, ot as getRecord, p as MAX_THREAD_EXPORT_PAGE_BYTES, pt as captureRecord, st as getRunInput } from "./ThreadStore-CEekRa80.mjs";
30
+ import { a as compileRegistrations, c as resolveDefinitionBinding, l as resolveWorkerBinding, n as CurrentBindingSelection, o as definitionDigestsEqual, s as makeLegacyWorkerBinding, t as BindingUnavailable, u as toolReplayContracts } from "./agent-registration-a6QYaG3h.mjs";
31
+ import { $ as makeJournalMetadata, A as subagentRequestedRecordId, B as toolStepSettledRecordId, C as runStartedBatchId, D as subagentLineageBatchId, E as subagentJoinedRecordId, F as toolCallResolutionBatchId, G as turnResponseBatch, I as toolCallResolvedRecordId, K as turnResponseBatchId, L as toolCallResultBatchId, M as subagentStartedRecordId, N as toolApprovalDecisionRecordId, O as subagentLineageRecordId, P as toolApprovalRequestRecordId, R as toolCallUnknownRecordId, S as runIdForSubmission, T as subagentJoinBatchId, U as turnCanonicalBatch, V as turnApprovalsBatchId, W as turnIdForRun, X as workerOriginRecordId, Y as workerInputRecordId, Z as workerReportRecordId, _ as projectRunJournalStream, a as childIdempotencyKeyFor, b as runDurationBatchId, c as compactionRecordId, d as markUnknownBatchId, et as toolCallSettledRecordId, f as modelResponseInterruptedBatchId, h as peerMessageRecordId, i as approvalDecisionBatchId, j as subagentStartedBatchId, k as subagentRequestedBatchId, l as firstWorkerInputRecordId, m as modelResponseRecordId, o as childThreadIdFor, p as modelResponseInterruptedRecordId, q as turnResultsBatch, r as agentUpdateRecordId, s as compactionBatchId, t as RunJournalError, u as initialRunJournal, w as runStartedRecordId, x as runDurationRecordId, y as runCompletedRecordId, z as toolStepSettledBatchId } from "./RunJournal-CPMKcfd0.mjs";
32
+ import { $ as ThreadTailRequest, B as ThreadPromptRead, F as ThreadIdentityRequest, I as ThreadMaterialization, J as ThreadStore, R as ThreadObservation, U as ThreadReader, V as ThreadRead, X as ThreadStoreError, Y as ThreadStoreDiagnostic, _t as isPreContinuationFact, bt as terminalUsageCharge, gt as executionRunIds, ht as canonicalRunIds, lt as readWorkerState, n as AppendRequest, ot as getRecord, p as MAX_THREAD_EXPORT_PAGE_BYTES, pt as captureRecord, st as getRunInput } from "./ThreadStore-EuUilthA.mjs";
32
33
  import { ScheduledInputRefused, ScheduledInputRetryable } from "./durable/Schedule.mjs";
33
34
  import { PreparedInputAdmission } from "./durable/PreparedInputAdmission.mjs";
34
35
  import { PreparedInput } from "./durable/Subscription.mjs";
35
36
  import { MessageDeliveryDriver, MessageDeliveryFailpoint, MessageDeliveryRecord, MessageDeliveryStore, prepareMessageDelivery } from "./durable/MessageDelivery.mjs";
36
37
  import { DurableRuntimeFailpoint } from "./durable/DurableFailpoint.mjs";
37
- import { _ as readRunContext, a as canonicalRecordBytes, b as reference, f as runEvidence, g as digestRunHistory, l as readContinuation, m as validateSuffix, n as CurrentRunWriter, s as makeProgressWriter, t as CurrentRunSettlement, u as readRunEvidenceSnapshot, x as resolveEvidence, y as RunContextReader } from "./RunContinuation-DHYNAQFi.mjs";
38
+ import { _ as readRunContext, a as canonicalRecordBytes, b as reference, f as runEvidence, g as digestRunHistory, l as readContinuation, m as validateSuffix, n as CurrentRunWriter, s as makeProgressWriter, t as CurrentRunSettlement, u as readRunEvidenceSnapshot, x as resolveEvidence, y as RunContextReader } from "./RunContinuation-BiyKJK32.mjs";
38
39
  import { MAX_WORK_CURSOR_CHARS, ThreadWorkDiscovery, ThreadWorkEntry, ThreadWorkRequest, WorkDiscoveryUnavailable, decodeWorkCursor, deliveryPredecessor, encodeWorkCursor, operationEvidence, resolveWorkEvidence, validateWorkPage, workId } from "./durable/ThreadWork.mjs";
39
40
  import { WakeScheduler } from "./durable/WakeScheduler.mjs";
40
41
  import { n as safeUnknownString, t as inspectForeignDiagnostic } from "./foreign-diagnostic-DBQ1XHKh.mjs";
41
- import { c as threadCreatedBatchId, l as threadCreatedRecordId, n as WorkerAdmissionPort, o as ensureThreadCreated, r as WorkerAdmissionRequest, s as ensureWorkerOrigin } from "./WorkerAdmission-DFVbbVh2.mjs";
42
+ import { c as threadCreatedBatchId, l as threadCreatedRecordId, n as WorkerAdmissionPort, o as ensureThreadCreated, r as WorkerAdmissionRequest, s as ensureWorkerOrigin } from "./WorkerAdmission-eBeXt_mu.mjs";
42
43
  import { i as unresolvedToolOperations, n as isUnresolvedToolOperation, r as toolOperationStates, t as initialDispatchBlockedTurns } from "./tool-operations-BXBmagY1.mjs";
43
44
  import { WorkerBudgetAuthorizer, WorkerConcurrencyLimit, WorkerConcurrencyResolver, WorkerHostAuthorizer, WorkerHostConfig, WorkerPolicyResolver } from "./durable/WorkerHost.mjs";
44
45
  import { OperationAuthorizationRequest, OperationAuthorizer, OperationDenied } from "./durable/OperationAuthorizer.mjs";
45
- import { o as makeRunWriter, r as RunStorage, s as StorageOwner } from "./RunStorage-uqPxps09.mjs";
46
+ import { o as makeRunWriter, r as RunStorage, s as StorageOwner } from "./RunStorage-CzutHJBE.mjs";
46
47
  import { SettlementPublication } from "./durable/SettlementPublisher.mjs";
47
48
  import { PendingSubmission, SettledSubmission } from "./durable/SubmissionStatus.mjs";
48
49
  import { DeclaredToolCallEvidence, ToolReconciler } from "./durable/ToolReconciler.mjs";
@@ -736,7 +737,7 @@ function hydratePart(part) {
736
737
  case "tool-approval-request": return Prompt.toolApprovalRequestPart(part);
737
738
  case "tool-approval-response": return Prompt.toolApprovalResponsePart(part);
738
739
  }
739
- throw new Error(`Unhandled Prompt part: ${part}`);
740
+ return part;
740
741
  }
741
742
  const hydrateMessage = (message) => {
742
743
  switch (message.role) {
@@ -754,7 +755,7 @@ const hydrateMessage = (message) => {
754
755
  content: message.content.map((p) => hydratePart(p))
755
756
  });
756
757
  }
757
- throw new Error(`Unhandled Prompt message: ${message}`);
758
+ return message;
758
759
  };
759
760
  /** Internal canonical projection; ownership comes from the ThreadStore read contract. */
760
761
  const preparePromptHistory = (prompt) => prompt.content.length > MAX_ENTRIES ? void 0 : {
@@ -851,7 +852,12 @@ const makeCommittedPromptSuffix = (original) => {
851
852
  }
852
853
  try {
853
854
  for (const fact of facts) {
854
- const owned = captureRecord(fact);
855
+ const captured = captureRecord(fact);
856
+ if (Result.isFailure(captured)) {
857
+ discard();
858
+ return;
859
+ }
860
+ const owned = captured.success;
855
861
  const payload = owned.canonical.payload;
856
862
  if (payload._tag !== "UserInputRecorded" && payload._tag !== "ModelResponseRecorded" && payload._tag !== "ToolCallSettled" && payload._tag !== "SubmissionSettled") {
857
863
  discard();
@@ -2384,7 +2390,7 @@ const makeWorkerRuntime = Effect.fnUntraced(function* (options) {
2384
2390
  ownerThreadId: context.source.threadId,
2385
2391
  messageId
2386
2392
  }).pipe(Effect.mapError(storageFailure("start")));
2387
- const replay = (saved) => Effect.gen(function* () {
2393
+ const replay = Effect.fnUntraced(function* (saved) {
2388
2394
  const currentPrevious = command.continuationOf === void 0 ? void 0 : yield* completedContinuation(context.source, command.continuationOf, command.target.id, command.delegationId, previous?.evidence);
2389
2395
  const replayPrincipal = yield* authorize("start", "send", void 0, currentPrevious?.evidence);
2390
2396
  yield* binding(command.target, "start");
@@ -2476,7 +2482,7 @@ const makeWorkerRuntime = Effect.fnUntraced(function* (options) {
2476
2482
  ownerThreadId: context.source.threadId,
2477
2483
  messageId
2478
2484
  }).pipe(Effect.mapError(storageFailure("followUp")));
2479
- const replay = (saved) => Effect.gen(function* () {
2485
+ const replay = Effect.fnUntraced(function* (saved) {
2480
2486
  const replayPrincipal = yield* authorize("followUp", "send", command.worker);
2481
2487
  yield* currentPolicy;
2482
2488
  return yield* send(origin, messageId, saved.envelope.input, command.encodedParameters, replayPrincipal, "followUp");
@@ -3147,6 +3153,7 @@ const make = Effect.fnUntraced(function* (bindings) {
3147
3153
  const store = yield* ThreadStore;
3148
3154
  const reader = ThreadReader.fromStore(store);
3149
3155
  const promptHistory = yield* makePromptHistoryCache();
3156
+ const unclaimedAdmissions = /* @__PURE__ */ new Map();
3150
3157
  const workDiscovery = yield* ThreadWorkDiscovery.pipe(Effect.provide(ThreadWorkDiscovery.layer), Effect.provideService(ThreadStore, store));
3151
3158
  const runStorage = yield* RunStorage;
3152
3159
  const storageOwner = yield* StorageOwner;
@@ -3170,8 +3177,10 @@ const make = Effect.fnUntraced(function* (bindings) {
3170
3177
  })));
3171
3178
  const operationAuthorizer = yield* OperationAuthorizer;
3172
3179
  const toolFailureObserver = yield* CurrentToolFailureObserver;
3180
+ const runServices = Context.make(CurrentToolFailureObserver, toolFailureObserver).pipe(Context.add(RunToolVisibility, runToolVisibility), Context.add(RunToolScheduling, runToolScheduling), Context.add(ContextCompactor, compactor), Context.add(RunContextPreparation, runContextPreparation));
3181
+ const journalServices = Context.make(ThreadReader, reader).pipe(Context.add(Crypto.Crypto, crypto));
3173
3182
  const withCrypto = (effect) => Effect.provideService(effect, Crypto.Crypto, crypto);
3174
- const readInitialJournal = (original, suffix) => initialContext(original).pipe(Effect.provideService(ThreadReader, reader), Effect.provideService(Crypto.Crypto, crypto), Effect.map((history) => history.concat(suffix)));
3183
+ const readInitialJournal = (original, suffix) => initialContext(original).pipe(Effect.provideContext(journalServices), Effect.map((history) => history.concat(suffix)));
3175
3184
  const resolutionIntentsFor = (snapshot) => {
3176
3185
  const intents = /* @__PURE__ */ new Map();
3177
3186
  for (const intent of snapshot.unknownResolutions) if (!intents.has(intent.toolCallId) || unknownResolutionKind(intent.resolution) === "factual") intents.set(intent.toolCallId, intent);
@@ -3257,6 +3266,7 @@ const make = Effect.fnUntraced(function* (bindings) {
3257
3266
  let context;
3258
3267
  let progress;
3259
3268
  let progressThrough;
3269
+ let operational = [];
3260
3270
  const invalid = (message) => ThreadStoreError.make({
3261
3271
  operation: "read Run continuation",
3262
3272
  message
@@ -3280,7 +3290,7 @@ const make = Effect.fnUntraced(function* (bindings) {
3280
3290
  const resolve = Effect.fnUntraced(function* (ref) {
3281
3291
  const found = byId.get(ref.recordId);
3282
3292
  if (found === void 0) {
3283
- yield* resolveEvidence(threadId, ref).pipe(Effect.provideService(ThreadReader, reader), Effect.provideService(Crypto.Crypto, crypto));
3293
+ yield* resolveEvidence(threadId, ref).pipe(Effect.provideContext(journalServices));
3284
3294
  return yield* invalid("Required Run evidence is absent from its locator; rebuild the index explicitly");
3285
3295
  }
3286
3296
  if (!canonicalRunIds(found.record).includes(runId)) return yield* invalid("Run continuation references another owner");
@@ -3304,7 +3314,7 @@ const make = Effect.fnUntraced(function* (bindings) {
3304
3314
  const cachedContext = resolvedContext;
3305
3315
  if (cachedContext?.threadId === threadId && cachedContext.recordId === cursor.savedContext.recordId) saved = cachedContext.value;
3306
3316
  else {
3307
- saved = yield* readRunContext(initial, input, cursor.savedContext.recordId).pipe(Effect.provide(RunContextReader.layer(threadId)), Effect.provideService(ThreadReader, reader), Effect.provideService(Crypto.Crypto, crypto), Effect.mapError(() => invalid("Saved original context cannot be resolved from its evidence")));
3317
+ saved = yield* readRunContext(initial, input, cursor.savedContext.recordId).pipe(Effect.provide(RunContextReader.layer(threadId)), Effect.provideContext(journalServices), Effect.mapError(() => invalid("Saved original context cannot be resolved from its evidence")));
3308
3318
  resolvedContext = {
3309
3319
  threadId,
3310
3320
  recordId: cursor.savedContext.recordId,
@@ -3325,20 +3335,20 @@ const make = Effect.fnUntraced(function* (bindings) {
3325
3335
  context = saved;
3326
3336
  progress = cursor;
3327
3337
  progressThrough = envelope.throughSequence;
3338
+ operational = envelope.operational;
3328
3339
  }
3329
3340
  }
3330
- const records = [...new Map([...identity.records.filter((entry) => entry.sequence <= throughSequence), ...selected].map((entry) => [entry.sequence, entry])).values()].sort((left, right) => left.sequence - right.sequence);
3331
3341
  return {
3332
- canonical: Stream.fromIterable(records),
3342
+ records: [...new Map([...identity.records.filter((entry) => entry.sequence <= throughSequence), ...selected].map((entry) => [entry.sequence, entry])).values()].sort((left, right) => left.sequence - right.sequence),
3333
3343
  context,
3334
3344
  progress,
3335
- progressThrough
3345
+ progressThrough,
3346
+ operational
3336
3347
  };
3337
3348
  });
3338
3349
  const readControl = Effect.fnUntraced(function* (threadId, submissionIds) {
3339
3350
  const tail = yield* store.inspectTail(ThreadTailRequest.make({ threadId }));
3340
- const view = yield* recoveryView(threadId, tail.tailSequence, submissionIds);
3341
- return yield* Stream.runCollect(view.canonical.pipe(Stream.filter(controlRecords(submissionIds))));
3351
+ return (yield* recoveryView(threadId, tail.tailSequence, submissionIds)).records.filter(controlRecords(submissionIds));
3342
3352
  });
3343
3353
  const readAllTolerant = (threadId, submissionIds) => Effect.suspend(() => readControl(threadId, submissionIds).pipe(Effect.map((records) => ({
3344
3354
  records,
@@ -3360,7 +3370,7 @@ const make = Effect.fnUntraced(function* (bindings) {
3360
3370
  submissionIds
3361
3371
  };
3362
3372
  return {
3363
- records: yield* recoveryView(threadId, tail.value.tailSequence, submissionIds).pipe(Effect.flatMap((view) => Stream.runCollect(view.canonical.pipe(Stream.filter(controlRecords(submissionIds))))), Effect.catchTag("ThreadNotMaterialized", (error) => ThreadStoreError.make({
3373
+ records: yield* recoveryView(threadId, tail.value.tailSequence, submissionIds).pipe(Effect.map((view) => view.records.filter(controlRecords(submissionIds))), Effect.catchTag("ThreadNotMaterialized", (error) => ThreadStoreError.make({
3364
3374
  operation: "read recovery history",
3365
3375
  message: `Thread ${threadId} disappeared after its recovery tail was captured`,
3366
3376
  cause: error
@@ -3719,7 +3729,7 @@ const make = Effect.fnUntraced(function* (bindings) {
3719
3729
  const progressWriters = /* @__PURE__ */ new WeakMap();
3720
3730
  const activeProgress = /* @__PURE__ */ new Map();
3721
3731
  const withProgress = Effect.fnUntraced(function* (writer) {
3722
- const progress = activeProgress.get(writer.threadId)?.writer ?? (yield* makeProgressWriter(writer.threadId, config.deploymentId).pipe(Effect.provideService(ThreadReader, reader), Effect.provideService(Crypto.Crypto, crypto)));
3732
+ const progress = activeProgress.get(writer.threadId)?.writer ?? (yield* makeProgressWriter(writer.threadId, config.deploymentId).pipe(Effect.provideContext(journalServices)));
3723
3733
  const owned = {
3724
3734
  ...writer,
3725
3735
  append: (batch) => progress.commit(batch).pipe(Effect.provideService(CurrentRunWriter, writer), Effect.tapError(() => writer.checkActive))
@@ -3747,8 +3757,8 @@ const make = Effect.fnUntraced(function* (bindings) {
3747
3757
  });
3748
3758
  const progressStore = ThreadStore.of({
3749
3759
  ...store,
3750
- append: (request) => Effect.gen(function* () {
3751
- const progress = activeProgress.get(request.threadId)?.writer ?? (yield* makeProgressWriter(request.threadId, config.deploymentId).pipe(Effect.provideService(ThreadReader, reader), Effect.provideService(Crypto.Crypto, crypto)));
3760
+ append: Effect.fnUntraced(function* (request) {
3761
+ const progress = activeProgress.get(request.threadId)?.writer ?? (yield* makeProgressWriter(request.threadId, config.deploymentId).pipe(Effect.provideContext(journalServices)));
3752
3762
  let tail = { sequence: request.expectedTailSequence };
3753
3763
  return yield* progress.commit(request.batch).pipe(Effect.provideService(CurrentRunWriter, {
3754
3764
  threadId: request.threadId,
@@ -3776,7 +3786,7 @@ const make = Effect.fnUntraced(function* (bindings) {
3776
3786
  threadId: ctx.threadId,
3777
3787
  tail: ctx.tail,
3778
3788
  withProgress: ctx.withProgress,
3779
- publishSettlement: (prepared, executions) => Effect.gen(function* () {
3789
+ publishSettlement: Effect.fnUntraced(function* (prepared, executions) {
3780
3790
  let tail = yield* ctx.tail;
3781
3791
  for (let retries = 0;; retries++) {
3782
3792
  const result = yield* runStorage.publishSettlement(SettlementPublication.make({
@@ -4079,23 +4089,26 @@ const make = Effect.fnUntraced(function* (bindings) {
4079
4089
  sequence: result.firstSequence
4080
4090
  });
4081
4091
  });
4082
- const readRunStart = Effect.fnUntraced(function* (threadId, runId) {
4083
- const loaded = yield* reader.readExecution({
4084
- threadId,
4085
- runId
4086
- }).pipe(Effect.catchTag("ThreadNotMaterialized", () => Effect.succeed(Option.none())));
4087
- if (Option.isNone(loaded)) return void 0;
4092
+ const readRunStart = Effect.fnUntraced(function* (threadId, runId, operational) {
4093
+ if (operational === void 0) {
4094
+ const loaded = yield* reader.readExecution({
4095
+ threadId,
4096
+ runId
4097
+ }).pipe(Effect.catchTag("ThreadNotMaterialized", () => Effect.succeed(Option.none())));
4098
+ if (Option.isNone(loaded)) return void 0;
4099
+ operational = loaded.value.operational;
4100
+ }
4088
4101
  const recordId = runStartedRecordId(runId);
4089
- const starts = loaded.value.operational.filter(({ payload }) => payload._tag === "RunStarted");
4090
- const existing = loaded.value.operational.find((record) => record.recordId === recordId);
4102
+ const starts = operational.filter(({ payload }) => payload._tag === "RunStarted");
4103
+ const existing = operational.find((record) => record.recordId === recordId);
4091
4104
  if (starts.length > 1 || starts.length === 1 && starts[0]?.recordId !== recordId || existing !== void 0 && (existing.payload._tag !== "RunStarted" || existing.payload.runId !== runId)) return yield* RunJournalError.make({ message: `Run ${runId} has conflicting active start state` });
4092
4105
  return existing;
4093
4106
  });
4094
- const makeRunStart = Effect.fnUntraced(function* (submission, maxDurationMillis, records) {
4107
+ const makeRunStart = Effect.fnUntraced(function* (submission, maxDurationMillis, records, operational) {
4095
4108
  const writer = yield* CurrentRunWriter;
4096
4109
  const runId = runIdForSubmission(submission.submissionId);
4097
4110
  const recordId = runStartedRecordId(runId);
4098
- const existing = yield* readRunStart(submission.threadId, runId);
4111
+ const existing = yield* readRunStart(submission.threadId, runId, operational);
4099
4112
  let start;
4100
4113
  let allowance = maxDurationMillis;
4101
4114
  let committed = existing !== void 0;
@@ -4942,1474 +4955,1484 @@ const make = Effect.fnUntraced(function* (bindings) {
4942
4955
  })).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
4943
4956
  knownIds.add(recordId);
4944
4957
  });
4945
- /**
4946
- * Drive the shared interpreter Effect with history rebuilt by the run journal, commit
4947
- * each Turn under the local owner, and watch for durable abort intent. Engine Run failures settle `failed`; coordinator failures abort the
4948
- * Attempt cleanly with the obligation still owed.
4949
- *
4950
- * The interpreter supplies validated response, closed Tool-result, and completion facts.
4951
- * Responses precede approval and effectful dispatch; readonly responses may join their closed
4952
- * results. Tool results precede input drains and the next Turn. A no-tool response and Run
4953
- * completion share one batch. A completion Tool's result
4954
- * precedes its terminal-only completion batch, so recovery can repeat a pure output projection
4955
- * without replaying the handler. Pending batches resume from their canonical declarations.
4956
- */
4957
- const runModel = (agent, ctx, submission, session, records, canonical, initialJournal, canonicalThrough, progressThrough, continuation, priorContext, journalMetadata, lineage, approvalDecisions, currentContracts, runTiming, yieldAfter) => Effect.gen(function* () {
4958
- const submissionId = submission.submissionId;
4959
- const runId = runIdForSubmission(submissionId);
4960
- const boundaries = [];
4961
- const cached = projectedJournal;
4962
- const projectionThrough = Math.max(progressThrough ?? 0, records.at(-1)?.sequence ?? 0);
4963
- const originalInput = records.find(({ record: { payload } }) => payload._tag === "UserInputRecorded" && payload.kind === "user" && payload.submissionId === submissionId);
4964
- if (originalInput === void 0) return yield* RunJournalError.make({ message: "Run has no original context boundary" });
4965
- const historyEvidence = /* @__PURE__ */ new Map();
4966
- const retainHistory = (entry) => {
4967
- if (priorContext === void 0 && entry.sequence < originalInput.sequence) historyEvidence.set(entry.record.recordId, entry);
4968
- };
4969
- let journal = cached !== void 0 && cached.threadId === ctx.threadId && cached.through === projectionThrough && cached.runId === runId && cached.contextRecordId === priorContext?.recordId ? (boundaries.push(...cached.boundaries), cached.contextEvidence.forEach(retainHistory), cached.journal) : yield* projectRunJournalStream(canonical, runId, (boundary) => boundaries.push(boundary), priorContext, journalMetadata, priorContext === void 0 ? retainHistory : void 0);
4970
- if (initialJournal?.prefix !== void 0) {
4971
- const prompt = initialJournal.prefix.prompt;
4972
- journal = {
4973
- ...journal,
4974
- prompt,
4975
- historyBefore: prompt
4958
+ const runModel = Effect.fnUntraced(
4959
+ /**
4960
+ * Drive the shared interpreter Effect with history rebuilt by the run journal, commit
4961
+ * each Turn under the local owner, and watch for durable abort intent. Engine Run failures settle `failed`; coordinator failures abort the
4962
+ * Attempt cleanly with the obligation still owed.
4963
+ *
4964
+ * The interpreter supplies validated response, closed Tool-result, and completion facts.
4965
+ * Responses precede approval and effectful dispatch; readonly responses may join their closed
4966
+ * results. Tool results precede input drains and the next Turn. A no-tool response and Run
4967
+ * completion share one batch. A completion Tool's result
4968
+ * precedes its terminal-only completion batch, so recovery can repeat a pure output projection
4969
+ * without replaying the handler. Pending batches resume from their canonical declarations.
4970
+ */
4971
+ function* (agent, ctx, submission, session, records, canonical, initialJournal, canonicalThrough, progressThrough, continuation, priorContext, journalMetadata, lineage, approvalDecisions, currentContracts, runTiming, yieldAfter) {
4972
+ const submissionId = submission.submissionId;
4973
+ const runId = runIdForSubmission(submissionId);
4974
+ const boundaries = [];
4975
+ const cached = projectedJournal;
4976
+ const projectionThrough = Math.max(progressThrough ?? 0, records.at(-1)?.sequence ?? 0);
4977
+ const originalInput = records.find(({ record: { payload } }) => payload._tag === "UserInputRecorded" && payload.kind === "user" && payload.submissionId === submissionId);
4978
+ if (originalInput === void 0) return yield* RunJournalError.make({ message: "Run has no original context boundary" });
4979
+ const historyEvidence = /* @__PURE__ */ new Map();
4980
+ const retainHistory = (entry) => {
4981
+ if (priorContext === void 0 && entry.sequence < originalInput.sequence) historyEvidence.set(entry.record.recordId, entry);
4976
4982
  };
4977
- }
4978
- journalMetadata = void 0;
4979
- historyEvidence.forEach((entry, id) => {
4980
- if (entry.sequence >= journal.historyFrom) historyEvidence.delete(id);
4981
- });
4982
- projectedJournal = {
4983
- threadId: ctx.threadId,
4984
- through: CanonicalSequence.make(projectionThrough),
4985
- runId,
4986
- contextRecordId: priorContext?.recordId,
4987
- contextEvidence: [...historyEvidence.values()],
4988
- journal,
4989
- boundaries
4990
- };
4991
- if (continuation !== void 0) {
4992
- const accounting = continuation.accounting;
4993
- if ([
4994
- "committedTurns",
4995
- "toolCalls",
4996
- "programmaticToolCalls",
4997
- "consecutiveToolFailures",
4998
- "finalizationUsed",
4999
- "modelRestarts"
5000
- ].some((field) => (journal.policyUsage[field] ?? 0) !== accounting[field]) || [
5001
- "modelCalls",
5002
- "inputTokens",
5003
- "outputTokens",
5004
- "lastInputTokens",
5005
- "lastOutputTokens",
5006
- "costMicrousd"
5007
- ].some((field) => journal.usage[field] !== accounting[field]) || (journal.usage.unobservedModelCalls ?? 0) !== accounting.unobservedModelCalls) return yield* RunJournalError.make({ message: "Canonical continuation accounting differs from its exact execution evidence" });
5008
- }
5009
- const childLineage = records.find(({ record }) => record.recordId === subagentLineageRecordId(submission.threadId))?.record.payload;
5010
- const inheritedGrant = submission.workerAdmission?.origin.grant ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.grant : void 0);
5011
- const delegationDepth = submission.workerAdmission?.origin.depth ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.parentLink.depth : 0);
5012
- const inheritedBudget = submission.workerAdmission?.origin.budget ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.budget : void 0);
5013
- if (submission.parentLinkage !== void 0 && (childLineage?._tag !== "SubagentLineageRecorded" || childLineage.parentSubmissionId !== submission.parentLinkage.parentSubmissionId || childLineage.parentLink.parentToolCallId !== submission.parentLinkage.parentToolCallId || !definitionDigestsEqual(childLineage.childDefinitionDigests, submission.agentDigests) || childLineage.childInputDigest !== submission.inputDigest)) return yield* RunJournalError.make({ message: "The child Run has no matching canonical lineage and execution bounds" });
5014
- const completionTools = [...agent.definition.completion === void 0 ? [] : [agent.definition.completion.tool], ...agent.definition.completionFromTools?.map((declaration) => declaration.tool) ?? []];
5015
- const pending = yield* pendingToolBatchFor(records, runId, completionTools);
5016
- const resumeProjection = pending === void 0 ? journal : yield* projectRunJournalStream(withoutPendingBatch(canonical, pending, runId), runId, void 0, priorContext);
5017
- if (initialJournal !== void 0 && (journal.committedTurns !== 0 || journal.historyFrom !== 1 || journal.contextWindowId !== void 0 || historyEvidence.size !== 0 || pending !== void 0 || boundaries.some((boundary) => boundary.incomplete))) initialJournal.cacheable = false;
5018
- if (initialJournal?.cacheable) initialJournal.history = initialJournal.prefix ?? preparePromptHistory(journal.historyBefore);
5019
- if (initialJournal !== void 0) initialJournal.records = void 0;
5020
- const rolloverOperation = journal.pendingContextToolCallId === void 0 ? void 0 : operationsFor(records, runId).get(journal.pendingContextToolCallId);
5021
- const rolloverTool = rolloverOperation === void 0 ? void 0 : agent.definition.toolkit.tools[rolloverOperation.toolName];
5022
- const pendingContextToolCallId = rolloverOperation !== void 0 && rolloverTool !== void 0 && Context.get(rolloverTool.annotations, ContextRolloverTool) && currentContracts[rolloverOperation.toolName] === rolloverOperation.replay ? journal.pendingContextToolCallId : void 0;
5023
- const applicationCalls = pending?.calls.filter((call) => !call.providerExecuted);
5024
- const completionCandidate = applicationCalls?.length === 1 && completionTools.some((tool) => tool === applicationCalls[0]?.name) && pending?.settled.some((result) => result.id === applicationCalls[0]?.id && !result.isFailure) ? applicationCalls[0] : void 0;
5025
- const settledCompletion = pending !== void 0 && completionCandidate !== void 0 && supportsOperation(OpenToolCallEvidence.make({
5026
- toolCallId: Schema.decodeSync(ToolCallId)(completionCandidate.id),
5027
- toolName: completionCandidate.name,
5028
- turn: pending.turn
5029
- }), pending.toolOperations.find((operation) => operation.toolCallId === completionCandidate.id), {
5030
- definition: agent.definition,
5031
- contracts: currentContracts
5032
- }) ? Schema.decodeSync(ToolCallId)(completionCandidate.id) : void 0;
5033
- const knownIds = knownRecordIdsOf(records);
5034
- const stepOutputs = /* @__PURE__ */ new Map();
5035
- for (const envelope of records) {
5036
- const payload = envelope.record.payload;
5037
- if (payload._tag === "ToolStepSettled" && payload.runId === runId) stepOutputs.set(toolStepSettledRecordId(runId, payload.toolCallId, payload.stepName), payload.output);
5038
- }
5039
- const canonicalApprovalDecisions = /* @__PURE__ */ new Map();
5040
- const approvalRequestedTurns = /* @__PURE__ */ new Set();
5041
- for (const envelope of records) {
5042
- const payload = envelope.record.payload;
5043
- if (payload._tag === "ToolApprovalDecided" && payload.runId === runId) canonicalApprovalDecisions.set(payload.toolCallId, payload.decision);
5044
- else if (payload._tag === "ToolApprovalRequested" && payload.runId === runId) approvalRequestedTurns.add(payload.turn);
5045
- }
5046
- const approvalIntents = /* @__PURE__ */ new Map();
5047
- for (const intent of approvalDecisions) approvalIntents.set(intent.toolCallId, intent);
5048
- const joinedInputEnvelopes = /* @__PURE__ */ new Map();
5049
- let lastHostResponseSequence;
5050
- for (const envelope of records) {
5051
- const payload = envelope.record.payload;
5052
- if (payload._tag === "UserInputRecorded" && payload.runId === runId && payload.submissionId !== void 0 && payload.submissionId !== submissionId) joinedInputEnvelopes.set(payload.submissionId, envelope);
5053
- else if (payload._tag === "ModelResponseRecorded" && payload.runId === runId) {
5054
- if (lastHostResponseSequence === void 0 || envelope.sequence > lastHostResponseSequence) lastHostResponseSequence = envelope.sequence;
4983
+ const freshPrefix = priorContext === void 0 && initialJournal?.prefix !== void 0 && initialJournal.records?.length === 1 && initialJournal.records[0] === originalInput ? initialJournal.prefix.prompt : void 0;
4984
+ let journal = freshPrefix !== void 0 ? initialRunJournal(freshPrefix) : cached !== void 0 && cached.threadId === ctx.threadId && cached.through === projectionThrough && cached.runId === runId && cached.contextRecordId === priorContext?.recordId ? (boundaries.push(...cached.boundaries), cached.contextEvidence.forEach(retainHistory), cached.journal) : yield* projectRunJournalStream(canonical, runId, (boundary) => boundaries.push(boundary), priorContext, journalMetadata, priorContext === void 0 ? retainHistory : void 0);
4985
+ if (initialJournal?.prefix !== void 0) {
4986
+ const prompt = initialJournal.prefix.prompt;
4987
+ journal = {
4988
+ ...journal,
4989
+ prompt,
4990
+ historyBefore: prompt
4991
+ };
5055
4992
  }
5056
- }
5057
- const stagedUsage = /* @__PURE__ */ new Map();
5058
- const committedUsageLengths = /* @__PURE__ */ new Map();
5059
- const committedUnobservedCalls = /* @__PURE__ */ new Map();
5060
- const usageForCommit = (turn) => {
5061
- const staged = stagedUsage.get(turn);
5062
- if (staged === void 0) return void 0;
5063
- const modelUsage = staged.modelUsage.slice(committedUsageLengths.get(turn) ?? 0);
5064
- if (modelUsage.length === 0) return void 0;
5065
- return {
5066
- modelUsage,
5067
- inputTokens: modelUsage.reduce((sum, call) => sum + call.inputTokens.total, 0),
5068
- outputTokens: modelUsage.reduce((sum, call) => sum + call.outputTokens.total, 0),
5069
- costMicrousd: modelUsage.reduce((sum, call) => sum + call.costMicrousd, 0)
4993
+ journalMetadata = void 0;
4994
+ historyEvidence.forEach((entry, id) => {
4995
+ if (entry.sequence >= journal.historyFrom) historyEvidence.delete(id);
4996
+ });
4997
+ projectedJournal = {
4998
+ threadId: ctx.threadId,
4999
+ through: CanonicalSequence.make(projectionThrough),
5000
+ runId,
5001
+ contextRecordId: priorContext?.recordId,
5002
+ contextEvidence: [...historyEvidence.values()],
5003
+ journal,
5004
+ boundaries
5070
5005
  };
5071
- };
5072
- const unobservedForCommit = (turn) => (stagedUnobservedCalls.get(turn) ?? 0) - (committedUnobservedCalls.get(turn) ?? 0);
5073
- const recordCommittedUsage = (batch) => {
5074
- for (const record of batch.records) {
5075
- if (record.payload._tag !== "ModelResponseRecorded" && record.payload._tag !== "ModelCallAborted") continue;
5076
- const payload = record.payload;
5077
- committedUsageLengths.set(payload.turn, (committedUsageLengths.get(payload.turn) ?? 0) + (payload.modelUsage?.length ?? 0));
5078
- committedUnobservedCalls.set(payload.turn, (committedUnobservedCalls.get(payload.turn) ?? 0) + (payload.unobservedModelCalls ?? 0));
5079
- }
5080
- progressWriters.get(ctx)?.stageUsage(runId, terminalUsageCharge(uncommittedModelUsage()));
5081
- };
5082
- const uncommittedModelUsage = () => [...stagedUsage.entries()].flatMap(([turn, usage]) => usage.modelUsage.slice(committedUsageLengths.get(turn) ?? 0));
5083
- const stagedUnobservedCalls = /* @__PURE__ */ new Map();
5084
- let interruptedUsage = records.some(({ record }) => record.payload._tag === "ModelResponseInterrupted" && record.payload.runId === runId);
5085
- const checkedUsageTotal = (field, value) => decodeUsageTotal(value).pipe(Effect.mapError((cause) => RunJournalError.make({
5086
- message: `Run usage summary exceeds safe-integer bounds at ${field}`,
5087
- cause
5088
- })));
5089
- const addUsageTotal = (field, left, right) => checkedUsageTotal(field, left + right);
5090
- const subtractUsageTotal = (field, left, right) => checkedUsageTotal(field, left - right);
5091
- const currentUsageSummary = () => Effect.gen(function* () {
5092
- const stagedCalls = [...stagedUsage.values()].flatMap((usage) => usage.modelUsage);
5093
- let unobservedModelCalls = journal.usage.unobservedModelCalls ?? 0;
5094
- for (const count of stagedUnobservedCalls.values()) unobservedModelCalls = yield* addUsageTotal("unobservedModelCalls", unobservedModelCalls, count);
5095
- const detailedCalls = [...journal.usage.modelUsage, ...stagedCalls];
5096
- const detailed = yield* summarizeModelUsage(detailedCalls, journal.usage.summarizedModelUsage).pipe(Effect.mapError((cause) => RunJournalError.make({
5097
- message: "Run detailed usage exceeds safe-integer accounting bounds",
5098
- cause
5099
- })));
5100
- let inputTokens = journal.usage.inputTokens;
5101
- let outputTokens = journal.usage.outputTokens;
5102
- let costMicrousd = journal.usage.costMicrousd;
5103
- for (const usage of stagedUsage.values()) {
5104
- inputTokens = yield* addUsageTotal("inputTokens", inputTokens, usage.inputTokens);
5105
- outputTokens = yield* addUsageTotal("outputTokens", outputTokens, usage.outputTokens);
5106
- costMicrousd = yield* addUsageTotal("costMicrousd", costMicrousd, usage.costMicrousd);
5107
- }
5108
- const modelCalls = yield* addUsageTotal("modelCalls", journal.usage.modelCalls, stagedCalls.length);
5109
- const legacyCalls = yield* subtractUsageTotal("legacy.modelCalls", modelCalls, detailed.modelCalls);
5110
- const legacyInput = yield* subtractUsageTotal("legacy.inputTokens", inputTokens, detailed.inputTokens.total);
5111
- const legacyOutput = yield* subtractUsageTotal("legacy.outputTokens", outputTokens, detailed.outputTokens.total);
5112
- const legacyCost = yield* subtractUsageTotal("legacy.costMicrousd", costMicrousd, detailed.costMicrousd);
5113
- if (legacyCalls === 0 && (legacyInput !== 0 || legacyOutput !== 0 || legacyCost !== 0)) return yield* RunJournalError.make({ message: "Run aggregate usage has legacy totals without a legacy model call" });
5114
- const byModel = [...detailed.byModel];
5115
- if (legacyCalls > 0) {
5116
- const existingIndex = byModel.findIndex((group) => group.provider === "unknown" && group.model === "legacy-record" && group.responseModel === void 0 && group.serviceTier === void 0 && group.pricingVersion === void 0);
5117
- const existing = existingIndex < 0 ? void 0 : byModel[existingIndex];
5118
- const legacyGroup = ModelUsageGroup.make({
5119
- provider: "unknown",
5120
- model: "legacy-record",
5121
- modelCalls: yield* addUsageTotal("byModel.modelCalls", existing?.modelCalls ?? 0, legacyCalls),
5122
- inputTokens: InputTokenUsage.make({
5123
- total: yield* addUsageTotal("byModel.inputTokens.total", existing?.inputTokens.total ?? 0, legacyInput),
5124
- uncached: yield* addUsageTotal("byModel.inputTokens.uncached", existing?.inputTokens.uncached ?? 0, legacyInput),
5125
- cacheRead: existing?.inputTokens.cacheRead ?? 0,
5126
- cacheWrite: existing?.inputTokens.cacheWrite ?? 0
5127
- }),
5128
- outputTokens: OutputTokenUsage.make({
5129
- total: yield* addUsageTotal("byModel.outputTokens.total", existing?.outputTokens.total ?? 0, legacyOutput),
5130
- text: yield* addUsageTotal("byModel.outputTokens.text", existing?.outputTokens.text ?? 0, legacyOutput),
5131
- reasoning: existing?.outputTokens.reasoning ?? 0
5132
- }),
5133
- costMicrousd: yield* addUsageTotal("byModel.costMicrousd", existing?.costMicrousd ?? 0, legacyCost)
5134
- });
5135
- if (existingIndex < 0) byModel.push(legacyGroup);
5136
- else byModel[existingIndex] = legacyGroup;
5006
+ if (continuation !== void 0) {
5007
+ const accounting = continuation.accounting;
5008
+ if ([
5009
+ "committedTurns",
5010
+ "toolCalls",
5011
+ "programmaticToolCalls",
5012
+ "consecutiveToolFailures",
5013
+ "finalizationUsed",
5014
+ "modelRestarts"
5015
+ ].some((field) => (journal.policyUsage[field] ?? 0) !== accounting[field]) || [
5016
+ "modelCalls",
5017
+ "inputTokens",
5018
+ "outputTokens",
5019
+ "lastInputTokens",
5020
+ "lastOutputTokens",
5021
+ "costMicrousd"
5022
+ ].some((field) => journal.usage[field] !== accounting[field]) || (journal.usage.unobservedModelCalls ?? 0) !== accounting.unobservedModelCalls) return yield* RunJournalError.make({ message: "Canonical continuation accounting differs from its exact execution evidence" });
5137
5023
  }
5138
- const uncached = yield* addUsageTotal("inputTokens.uncached", detailed.inputTokens.uncached, legacyInput);
5139
- const text = yield* addUsageTotal("outputTokens.text", detailed.outputTokens.text, legacyOutput);
5140
- return RunUsageSummary.make({
5141
- ...legacyCalls === 0 && detailed.webSearchCalls !== void 0 ? { webSearchCalls: detailed.webSearchCalls } : {},
5142
- modelCalls,
5143
- inputTokens: InputTokenUsage.make({
5144
- total: inputTokens,
5145
- uncached,
5146
- cacheRead: detailed.inputTokens.cacheRead,
5147
- cacheWrite: detailed.inputTokens.cacheWrite
5148
- }),
5149
- outputTokens: OutputTokenUsage.make({
5150
- total: outputTokens,
5151
- text,
5152
- reasoning: detailed.outputTokens.reasoning
5153
- }),
5154
- costMicrousd,
5155
- byModel,
5156
- unobservedModelCalls,
5157
- usageStatus: legacyCalls > 0 || unobservedModelCalls > 0 || interruptedUsage ? detailed.usageStatus === "unknown" ? "unknown" : "partial" : detailed.usageStatus,
5158
- pricingStatus: legacyCalls > 0 || unobservedModelCalls > 0 || interruptedUsage ? detailed.pricingStatus === "unknown" ? "unknown" : "partial" : detailed.pricingStatus
5159
- });
5160
- });
5161
- const activeExecution = yield* reader.readExecution({
5162
- threadId: ctx.threadId,
5163
- runId
5164
- });
5165
- const recordedCompletion = Option.isSome(activeExecution) ? activeExecution.value.operational.find((record) => record.recordId === runCompletedRecordId(runId))?.payload : void 0;
5166
- if (recordedCompletion !== void 0) {
5167
- if (recordedCompletion._tag !== "RunCompleted" || recordedCompletion.runId !== runId) return yield* RunJournalError.make({ message: `Run ${runId} has an invalid terminal completion marker` });
5168
- const response = [...records].reverse().find((envelope) => envelope.record.payload._tag === "ModelResponseRecorded" && envelope.record.payload.runId === runId)?.record.payload;
5169
- if (response?._tag !== "ModelResponseRecorded") return yield* RunJournalError.make({ message: `Run ${runId} has a terminal completion marker without a response` });
5170
- const calls = (yield* declaredToolCalls(response.messages)).application;
5171
- if (calls.length > 0) {
5172
- const call = calls[0];
5173
- const settled = call === void 0 ? void 0 : records.find(({ record }) => record.payload._tag === "ToolCallSettled" && record.payload.runId === runId && record.payload.toolCallId === call.id)?.record.payload;
5174
- if (calls.length !== 1 || call === void 0 || settled?._tag !== "ToolCallSettled" || settled.toolName !== call.name || settled.isFailure) return yield* RunJournalError.make({ message: `Run ${runId} has a terminal completion marker without one successful declared Tool result` });
5024
+ const childLineage = records.find(({ record }) => record.recordId === subagentLineageRecordId(submission.threadId))?.record.payload;
5025
+ const inheritedGrant = submission.workerAdmission?.origin.grant ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.grant : void 0);
5026
+ const delegationDepth = submission.workerAdmission?.origin.depth ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.parentLink.depth : 0);
5027
+ const inheritedBudget = submission.workerAdmission?.origin.budget ?? (childLineage?._tag === "SubagentLineageRecorded" ? childLineage.budget : void 0);
5028
+ if (submission.parentLinkage !== void 0 && (childLineage?._tag !== "SubagentLineageRecorded" || childLineage.parentSubmissionId !== submission.parentLinkage.parentSubmissionId || childLineage.parentLink.parentToolCallId !== submission.parentLinkage.parentToolCallId || !definitionDigestsEqual(childLineage.childDefinitionDigests, submission.agentDigests) || childLineage.childInputDigest !== submission.inputDigest)) return yield* RunJournalError.make({ message: "The child Run has no matching canonical lineage and execution bounds" });
5029
+ const completionTools = [...agent.definition.completion === void 0 ? [] : [agent.definition.completion.tool], ...agent.definition.completionFromTools?.map((declaration) => declaration.tool) ?? []];
5030
+ const pending = yield* pendingToolBatchFor(records, runId, completionTools);
5031
+ const resumeProjection = pending === void 0 ? journal : yield* projectRunJournalStream(withoutPendingBatch(canonical, pending, runId), runId, void 0, priorContext);
5032
+ if (initialJournal !== void 0 && (journal.committedTurns !== 0 || journal.historyFrom !== 1 || journal.contextWindowId !== void 0 || historyEvidence.size !== 0 || pending !== void 0 || boundaries.some((boundary) => boundary.incomplete))) initialJournal.cacheable = false;
5033
+ if (initialJournal?.cacheable) initialJournal.history = initialJournal.prefix ?? preparePromptHistory(journal.historyBefore);
5034
+ if (initialJournal !== void 0) initialJournal.records = void 0;
5035
+ const rolloverOperation = journal.pendingContextToolCallId === void 0 ? void 0 : operationsFor(records, runId).get(journal.pendingContextToolCallId);
5036
+ const rolloverTool = rolloverOperation === void 0 ? void 0 : agent.definition.toolkit.tools[rolloverOperation.toolName];
5037
+ const pendingContextToolCallId = rolloverOperation !== void 0 && rolloverTool !== void 0 && Context.get(rolloverTool.annotations, ContextRolloverTool) && currentContracts[rolloverOperation.toolName] === rolloverOperation.replay ? journal.pendingContextToolCallId : void 0;
5038
+ const applicationCalls = pending?.calls.filter((call) => !call.providerExecuted);
5039
+ const completionCandidate = applicationCalls?.length === 1 && completionTools.some((tool) => tool === applicationCalls[0]?.name) && pending?.settled.some((result) => result.id === applicationCalls[0]?.id && !result.isFailure) ? applicationCalls[0] : void 0;
5040
+ const settledCompletion = pending !== void 0 && completionCandidate !== void 0 && supportsOperation(OpenToolCallEvidence.make({
5041
+ toolCallId: Schema.decodeSync(ToolCallId)(completionCandidate.id),
5042
+ toolName: completionCandidate.name,
5043
+ turn: pending.turn
5044
+ }), pending.toolOperations.find((operation) => operation.toolCallId === completionCandidate.id), {
5045
+ definition: agent.definition,
5046
+ contracts: currentContracts
5047
+ }) ? Schema.decodeSync(ToolCallId)(completionCandidate.id) : void 0;
5048
+ const knownIds = knownRecordIdsOf(records);
5049
+ const stepOutputs = /* @__PURE__ */ new Map();
5050
+ for (const envelope of records) {
5051
+ const payload = envelope.record.payload;
5052
+ if (payload._tag === "ToolStepSettled" && payload.runId === runId) stepOutputs.set(toolStepSettledRecordId(runId, payload.toolCallId, payload.stepName), payload.output);
5175
5053
  }
5176
- return {
5177
- _tag: "completed",
5178
- result: recordedCompletion.output,
5179
- ...recordedCompletion.runDisposition === void 0 ? {} : { runDisposition: recordedCompletion.runDisposition },
5180
- ...recordedCompletion.finishReason === void 0 ? {} : { finishReason: recordedCompletion.finishReason },
5181
- ...recordedCompletion.exhausted === void 0 ? {} : { exhausted: recordedCompletion.exhausted },
5182
- usageSummary: yield* currentUsageSummary()
5183
- };
5184
- }
5185
- let ownerFirstSequence;
5186
- for (const envelope of records) {
5187
- const payload = envelope.record.payload;
5188
- if ("runId" in payload && payload.runId === runId) {
5189
- ownerFirstSequence = envelope.sequence;
5190
- break;
5054
+ const canonicalApprovalDecisions = /* @__PURE__ */ new Map();
5055
+ const approvalRequestedTurns = /* @__PURE__ */ new Set();
5056
+ for (const envelope of records) {
5057
+ const payload = envelope.record.payload;
5058
+ if (payload._tag === "ToolApprovalDecided" && payload.runId === runId) canonicalApprovalDecisions.set(payload.toolCallId, payload.decision);
5059
+ else if (payload._tag === "ToolApprovalRequested" && payload.runId === runId) approvalRequestedTurns.add(payload.turn);
5191
5060
  }
5192
- }
5193
- /** Only canonical joined inputs can require restoration from an earlier Attempt. */
5194
- let joinBacklog = joinedInputEnvelopes.size === 0 ? [] : void 0;
5195
- /** Joined inputs already handed to the engine during THIS Attempt (never re-deliver). */
5196
- const deliveredJoinInputs = /* @__PURE__ */ new Set();
5197
- const encodedParamsByCallId = /* @__PURE__ */ new Map();
5198
- const declaredNamesByCallId = /* @__PURE__ */ new Map();
5199
- const subagentState = subagentRecordsOf(records, runId);
5200
- const declaredToolIds = new Set(subagentState.declaredNames.keys());
5201
- if (declaredToolIds.size > 4096) return yield* RunJournalError.make({ message: `Run exceeds the ${MAX_RUN_TOOL_CALL_IDENTITIES} Tool Call identity limit` });
5202
- for (const [callId, name] of subagentState.declaredNames) declaredNamesByCallId.set(callId, name);
5203
- if (pending !== void 0) for (const call of pending.calls) {
5204
- encodedParamsByCallId.set(call.id, call.params);
5205
- declaredNamesByCallId.set(call.id, call.name);
5206
- }
5207
- let resumeLeadingMessages;
5208
- let resumeResponseMessages;
5209
- if (pending !== void 0) {
5210
- const pendingMessages = yield* decodePrompt(pending.messages).pipe(Effect.mapError((cause) => RunJournalError.make({
5211
- message: "Pending ModelResponseRecorded messages are not Schema-encoded Prompt messages",
5212
- cause
5213
- })));
5214
- const firstAssistant = pendingMessages.content.findIndex((message) => message.role === "assistant");
5215
- if (firstAssistant > 0) resumeLeadingMessages = Prompt.fromMessages(pendingMessages.content.slice(0, firstAssistant).filter((message) => message.role !== "system"));
5216
- if (firstAssistant >= 0) resumeResponseMessages = Prompt.fromMessages(pendingMessages.content.slice(firstAssistant));
5217
- }
5218
- const initialDispatchProofTurns = new Set(initialDispatchBlockedTurns(records, runId));
5219
- let currentToolTurn = pending === void 0 ? void 0 : {
5220
- turn: pending.turn,
5221
- turnId: pending.turnId
5222
- };
5223
- const haltRef = yield* Ref.make(void 0);
5224
- const yieldSignal = yield* Deferred.make();
5225
- const recordHalt = (effect) => effect.pipe(Effect.tapError((failure) => failure instanceof ThreadStoreError && failure.cause instanceof AgentPersistenceCapacityError ? Effect.void : Ref.set(haltRef, failure)), Effect.catchCause((cause) => Effect.failCause(Cause.map(cause, (failure) => failure instanceof ThreadStoreError && failure.cause instanceof AgentPersistenceCapacityError ? failure.cause : new CoordinatorHalt(failure)))));
5226
- const checkpoint = recordHalt(Effect.gen(function* () {
5227
- const failure = yield* Ref.get(haltRef);
5228
- if (failure !== void 0) return yield* failure;
5229
- const progress = progressWriters.get(ctx);
5230
- if (progress !== void 0) yield* progress.check(runId).pipe(Effect.provideService(CurrentRunWriter, ctx));
5231
- }));
5232
- const responseGate = yield* Semaphore.make(1);
5233
- let deferredResponse;
5234
- const acceptResponseDeclarations = (batch) => {
5235
- for (const record of batch.records) {
5236
- if (record.payload._tag !== "ModelResponseRecorded") continue;
5237
- for (const call of record.payload.toolOperations) {
5238
- declaredToolIds.add(call.toolCallId);
5239
- declaredNamesByCallId.set(call.toolCallId, call.toolName);
5061
+ const approvalIntents = /* @__PURE__ */ new Map();
5062
+ for (const intent of approvalDecisions) approvalIntents.set(intent.toolCallId, intent);
5063
+ const joinedInputEnvelopes = /* @__PURE__ */ new Map();
5064
+ let lastHostResponseSequence;
5065
+ for (const envelope of records) {
5066
+ const payload = envelope.record.payload;
5067
+ if (payload._tag === "UserInputRecorded" && payload.runId === runId && payload.submissionId !== void 0 && payload.submissionId !== submissionId) joinedInputEnvelopes.set(payload.submissionId, envelope);
5068
+ else if (payload._tag === "ModelResponseRecorded" && payload.runId === runId) {
5069
+ if (lastHostResponseSequence === void 0 || envelope.sequence > lastHostResponseSequence) lastHostResponseSequence = envelope.sequence;
5240
5070
  }
5241
5071
  }
5242
- };
5243
- const promoteResponse = Effect.gen(function* () {
5244
- const halted = yield* Ref.get(haltRef);
5245
- if (halted !== void 0) return yield* halted;
5246
- const deferred = deferredResponse;
5247
- if (deferred === void 0) return;
5248
- const record = deferred.batch.records[0];
5249
- if (record?.payload._tag !== "ModelResponseRecorded") return yield* RunJournalError.make({ message: "Deferred Turn has no owned response" });
5250
- const calls = yield* declaredToolCalls(record.payload.messages);
5251
- const batch = CanonicalBatch.make({
5252
- ...deferred.batch,
5253
- batchId: turnResponseBatchId(runId, deferred.turn)
5254
- });
5255
- yield* appendBatch(ctx, batch);
5256
- acceptResponseDeclarations(batch);
5257
- for (const call of calls.application) encodedParamsByCallId.set(call.id, call.params);
5258
- recordCommittedUsage(batch);
5259
- for (const entry of batch.records) knownIds.add(entry.recordId);
5260
- deferredResponse = void 0;
5261
- yield* hit("turn:after-response-append");
5262
- });
5263
- const flushDeferredResponse = promoteResponse.pipe(Effect.tapError((failure) => failure instanceof ThreadStoreError && failure.cause instanceof AgentPersistenceCapacityError ? Effect.void : Ref.set(haltRef, failure)), responseGate.withPermits(1));
5264
- let initialHistoryLength = 0;
5265
- let initialInstructions = [];
5266
- const completionState = {};
5267
- const turnCounter = yield* Ref.make(journal.committedTurns + (journal.policyUsage.modelRestarts ?? 0));
5268
- const idGenerator = {
5269
- nextThreadId: Effect.succeed(submission.threadId),
5270
- nextRunId: Effect.succeed(runId),
5271
- nextTurnId: Ref.modify(turnCounter, (turn) => [turnIdForRun(runId, turn + 1), turn + 1])
5272
- };
5273
- const instructionView = (messages, instructions, insertWhenAbsent, priorRunPrefixLength) => {
5274
- const projected = [];
5275
- const lengths = [0];
5276
- let inserted = false;
5277
- for (const [index, message] of messages.entries()) {
5278
- if (index >= priorRunPrefixLength && message.role === "system") {
5279
- if (!inserted) projected.push(...instructions);
5280
- inserted = true;
5281
- } else projected.push(message);
5282
- lengths.push(projected.length);
5283
- }
5284
- if (!inserted && insertWhenAbsent) projected.push(...instructions);
5285
- return {
5286
- messages: projected,
5287
- prefixLength: (length) => lengths[length] ?? projected.length
5072
+ const stagedUsage = /* @__PURE__ */ new Map();
5073
+ const committedUsageLengths = /* @__PURE__ */ new Map();
5074
+ const committedUnobservedCalls = /* @__PURE__ */ new Map();
5075
+ const usageForCommit = (turn) => {
5076
+ const staged = stagedUsage.get(turn);
5077
+ if (staged === void 0) return void 0;
5078
+ const modelUsage = staged.modelUsage.slice(committedUsageLengths.get(turn) ?? 0);
5079
+ if (modelUsage.length === 0) return void 0;
5080
+ return {
5081
+ modelUsage,
5082
+ inputTokens: modelUsage.reduce((sum, call) => sum + call.inputTokens.total, 0),
5083
+ outputTokens: modelUsage.reduce((sum, call) => sum + call.outputTokens.total, 0),
5084
+ costMicrousd: modelUsage.reduce((sum, call) => sum + call.costMicrousd, 0)
5085
+ };
5288
5086
  };
5289
- };
5290
- const resumeContext = { prepare: ({ source }) => Effect.sync(() => {
5291
- const prefix = journal.committedTurns === 0 && priorContext !== void 0 ? priorContext.prompt.content.slice(priorContext.priorHistoryLength) : [];
5292
- const priorRunPrefixLength = journal.committedTurns === 0 ? resumeProjection.prompt.content.length : resumeProjection.historyBefore.content.length;
5293
- const view = instructionView(prefix.length === 0 ? resumeProjection.prompt.content : [...resumeProjection.prompt.content, ...prefix], initialInstructions, true, priorRunPrefixLength);
5294
- return {
5295
- prompt: Prompt.fromMessages([...view.messages, ...source.content.slice(initialHistoryLength)]),
5296
- priorRunPrefixLength: view.prefixLength(priorRunPrefixLength)
5087
+ const unobservedForCommit = (turn) => (stagedUnobservedCalls.get(turn) ?? 0) - (committedUnobservedCalls.get(turn) ?? 0);
5088
+ const recordCommittedUsage = (batch) => {
5089
+ for (const record of batch.records) {
5090
+ if (record.payload._tag !== "ModelResponseRecorded" && record.payload._tag !== "ModelCallAborted") continue;
5091
+ const payload = record.payload;
5092
+ committedUsageLengths.set(payload.turn, (committedUsageLengths.get(payload.turn) ?? 0) + (payload.modelUsage?.length ?? 0));
5093
+ committedUnobservedCalls.set(payload.turn, (committedUnobservedCalls.get(payload.turn) ?? 0) + (payload.unobservedModelCalls ?? 0));
5094
+ }
5095
+ progressWriters.get(ctx)?.stageUsage(runId, terminalUsageCharge(uncommittedModelUsage()));
5297
5096
  };
5298
- }) };
5299
- const externalContext = runContextPreparation.hook;
5300
- const needsContextReplay = priorContext !== void 0 || journal.committedTurns > 0;
5301
- const preparedContext = externalContext === void 0 ? needsContextReplay ? resumeContext : void 0 : { prepare: (request) => (needsContextReplay ? resumeContext.prepare(request) : Effect.succeed({
5302
- prompt: request.source,
5303
- priorRunPrefixLength: journal.historyBefore.content.length
5304
- })).pipe(Effect.flatMap(({ prompt, priorRunPrefixLength }) => externalContext.prepare({
5305
- ...request,
5306
- source: prompt,
5307
- priorRunPrefixLength
5308
- })), Effect.map((prepared) => {
5309
- if (prepared.rollover === void 0 || !knownIds.has(compactionRecordId(runId, request.turn, "rollover"))) return prepared;
5310
- const { rollover: _, ...retained } = prepared;
5311
- return retained;
5312
- })) };
5313
- const durability = {
5314
- toolResultMaxBytes: MAX_PERSISTED_JSON_BYTES,
5315
- checkpoint,
5316
- initialize: ({ initialHistory, priorHistoryLength }) => recordHalt(Effect.gen(function* () {
5317
- initialHistoryLength = initialHistory.content.length;
5318
- initialInstructions = initialHistory.content.slice(priorHistoryLength).filter((message) => message.role === "system");
5319
- if (priorContext !== void 0) return;
5320
- const recordId = decodeRecordIdSync(JSON.stringify(["run-context@1", runId]));
5321
- const prompt = yield* Schema.encodeEffect(Prompt.Prompt)(Prompt.fromMessages(initialHistory.content.slice(priorHistoryLength))).pipe(Effect.flatMap(decodePersisted), Effect.mapError((cause) => RunJournalError.make({
5322
- message: "Original Run context exceeds persistence bounds",
5097
+ const uncommittedModelUsage = () => [...stagedUsage.entries()].flatMap(([turn, usage]) => usage.modelUsage.slice(committedUsageLengths.get(turn) ?? 0));
5098
+ const stagedUnobservedCalls = /* @__PURE__ */ new Map();
5099
+ let interruptedUsage = records.some(({ record }) => record.payload._tag === "ModelResponseInterrupted" && record.payload.runId === runId);
5100
+ const checkedUsageTotal = (field, value) => decodeUsageTotal(value).pipe(Effect.mapError((cause) => RunJournalError.make({
5101
+ message: `Run usage summary exceeds safe-integer bounds at ${field}`,
5102
+ cause
5103
+ })));
5104
+ const subtractUsageTotal = (field, left, right) => checkedUsageTotal(field, left - right);
5105
+ const currentUsageSummary = () => Effect.gen(function* () {
5106
+ const stagedCalls = [...stagedUsage.values()].flatMap((usage) => usage.modelUsage);
5107
+ let unobservedModelCalls = journal.usage.unobservedModelCalls ?? 0;
5108
+ for (const count of stagedUnobservedCalls.values()) unobservedModelCalls += count;
5109
+ const detailedCalls = [...journal.usage.modelUsage, ...stagedCalls];
5110
+ const detailed = yield* summarizeModelUsage(detailedCalls, journal.usage.summarizedModelUsage).pipe(Effect.mapError((cause) => RunJournalError.make({
5111
+ message: "Run detailed usage exceeds safe-integer accounting bounds",
5323
5112
  cause
5324
5113
  })));
5325
- const history = Prompt.fromMessages(initialHistory.content.slice(0, priorHistoryLength));
5326
- const historyDigest = yield* withCrypto(digestPromptHistory(history, initialJournal?.history));
5327
- const retained = yield* Effect.forEach([...historyEvidence.values()].filter((entry) => entry.sequence < journal.historyFrom).sort((left, right) => left.sequence - right.sequence), (entry) => Effect.gen(function* () {
5328
- const full = yield* getRecord({
5329
- threadId: ctx.threadId,
5330
- recordId: entry.record.recordId
5331
- });
5332
- if (Option.isNone(full) || full.value.sequence !== entry.sequence) return yield* RunJournalError.make({ message: "Retained history has no exact canonical fact" });
5333
- return {
5334
- ...yield* withCrypto(reference(full.value.record)),
5335
- sequence: entry.sequence
5336
- };
5337
- }).pipe(Effect.provideService(ThreadReader, reader)));
5338
- const payload = yield* RunContextRecorded.makeEffect({
5339
- version: 1,
5340
- runId,
5341
- runScopedInput: prompt,
5342
- historyFrom: journal.historyFrom,
5343
- historyThrough: CanonicalSequence.make(originalInput.sequence - 1),
5344
- retained,
5345
- historyDigest,
5346
- priorHistoryLength,
5347
- ...journal.contextWindowId === void 0 ? {} : { contextWindowId: journal.contextWindowId }
5114
+ let inputTokens = journal.usage.inputTokens;
5115
+ let outputTokens = journal.usage.outputTokens;
5116
+ let costMicrousd = journal.usage.costMicrousd;
5117
+ for (const usage of stagedUsage.values()) {
5118
+ inputTokens += usage.inputTokens;
5119
+ outputTokens += usage.outputTokens;
5120
+ costMicrousd += usage.costMicrousd;
5121
+ }
5122
+ const modelCalls = journal.usage.modelCalls + stagedCalls.length;
5123
+ const legacyCalls = yield* subtractUsageTotal("legacy.modelCalls", modelCalls, detailed.modelCalls);
5124
+ const legacyInput = yield* subtractUsageTotal("legacy.inputTokens", inputTokens, detailed.inputTokens.total);
5125
+ const legacyOutput = yield* subtractUsageTotal("legacy.outputTokens", outputTokens, detailed.outputTokens.total);
5126
+ const legacyCost = yield* subtractUsageTotal("legacy.costMicrousd", costMicrousd, detailed.costMicrousd);
5127
+ if (legacyCalls === 0 && (legacyInput !== 0 || legacyOutput !== 0 || legacyCost !== 0)) return yield* RunJournalError.make({ message: "Run aggregate usage has legacy totals without a legacy model call" });
5128
+ const byModel = [...detailed.byModel];
5129
+ if (legacyCalls > 0) {
5130
+ const existingIndex = byModel.findIndex((group) => group.provider === "unknown" && group.model === "legacy-record" && group.responseModel === void 0 && group.serviceTier === void 0 && group.pricingVersion === void 0);
5131
+ const existing = existingIndex < 0 ? void 0 : byModel[existingIndex];
5132
+ const legacyGroup = yield* ModelUsageGroup.makeEffect({
5133
+ provider: "unknown",
5134
+ model: "legacy-record",
5135
+ modelCalls: (existing?.modelCalls ?? 0) + legacyCalls,
5136
+ inputTokens: {
5137
+ total: (existing?.inputTokens.total ?? 0) + legacyInput,
5138
+ uncached: (existing?.inputTokens.uncached ?? 0) + legacyInput,
5139
+ cacheRead: existing?.inputTokens.cacheRead ?? 0,
5140
+ cacheWrite: existing?.inputTokens.cacheWrite ?? 0
5141
+ },
5142
+ outputTokens: {
5143
+ total: (existing?.outputTokens.total ?? 0) + legacyOutput,
5144
+ text: (existing?.outputTokens.text ?? 0) + legacyOutput,
5145
+ reasoning: existing?.outputTokens.reasoning ?? 0
5146
+ },
5147
+ costMicrousd: (existing?.costMicrousd ?? 0) + legacyCost
5148
+ }).pipe(Effect.mapError((cause) => RunJournalError.make({
5149
+ message: "Run legacy usage exceeds safe-integer accounting bounds",
5150
+ cause
5151
+ })));
5152
+ if (existingIndex < 0) byModel.push(legacyGroup);
5153
+ else byModel[existingIndex] = legacyGroup;
5154
+ }
5155
+ return yield* RunUsageSummary.makeEffect({
5156
+ ...legacyCalls === 0 && detailed.webSearchCalls !== void 0 ? { webSearchCalls: detailed.webSearchCalls } : {},
5157
+ modelCalls,
5158
+ inputTokens: {
5159
+ total: inputTokens,
5160
+ uncached: detailed.inputTokens.uncached + legacyInput,
5161
+ cacheRead: detailed.inputTokens.cacheRead,
5162
+ cacheWrite: detailed.inputTokens.cacheWrite
5163
+ },
5164
+ outputTokens: {
5165
+ total: outputTokens,
5166
+ text: detailed.outputTokens.text + legacyOutput,
5167
+ reasoning: detailed.outputTokens.reasoning
5168
+ },
5169
+ costMicrousd,
5170
+ byModel,
5171
+ unobservedModelCalls,
5172
+ usageStatus: legacyCalls > 0 || unobservedModelCalls > 0 || interruptedUsage ? detailed.usageStatus === "unknown" ? "unknown" : "partial" : detailed.usageStatus,
5173
+ pricingStatus: legacyCalls > 0 || unobservedModelCalls > 0 || interruptedUsage ? detailed.pricingStatus === "unknown" ? "unknown" : "partial" : detailed.pricingStatus
5348
5174
  }).pipe(Effect.mapError((cause) => RunJournalError.make({
5349
- message: "Original Run context mapping exceeds its bounds",
5175
+ message: "Run usage summary exceeds safe-integer accounting bounds",
5350
5176
  cause
5351
5177
  })));
5352
- yield* (yield* CurrentRunStart).commit(yield* makeEnvelope(recordId, payload));
5353
- knownIds.add(runStartedRecordId(runId));
5354
- knownIds.add(recordId);
5355
- historyEvidence.clear();
5356
- projectedJournal = void 0;
5357
- })),
5358
- commitModelRestart: (restart) => recordHalt(Effect.gen(function* () {
5359
- if (knownIds.has(modelResponseRecordId(runId, restart.turn))) return yield* RunJournalError.make({ message: "Cannot restart a canonical model response" });
5360
- const recordId = decodeRecordIdSync(`model-aborted:${runId}:${restart.restart}`);
5361
- const record = yield* makeEnvelope(recordId, ModelCallAborted.make({
5362
- runId,
5363
- ...restart,
5364
- reason: "joined-input",
5365
- modelUsage: usageForCommit(restart.turn)?.modelUsage ?? [],
5366
- unobservedModelCalls: unobservedForCommit(restart.turn)
5367
- }));
5178
+ });
5179
+ const activeExecution = yield* reader.readExecution({
5180
+ threadId: ctx.threadId,
5181
+ runId
5182
+ });
5183
+ const recordedCompletion = Option.isSome(activeExecution) ? activeExecution.value.operational.find((record) => record.recordId === runCompletedRecordId(runId))?.payload : void 0;
5184
+ if (recordedCompletion !== void 0) {
5185
+ if (recordedCompletion._tag !== "RunCompleted" || recordedCompletion.runId !== runId) return yield* RunJournalError.make({ message: `Run ${runId} has an invalid terminal completion marker` });
5186
+ const response = [...records].reverse().find((envelope) => envelope.record.payload._tag === "ModelResponseRecorded" && envelope.record.payload.runId === runId)?.record.payload;
5187
+ if (response?._tag !== "ModelResponseRecorded") return yield* RunJournalError.make({ message: `Run ${runId} has a terminal completion marker without a response` });
5188
+ const calls = (yield* declaredToolCalls(response.messages)).application;
5189
+ if (calls.length > 0) {
5190
+ const call = calls[0];
5191
+ const settled = call === void 0 ? void 0 : records.find(({ record }) => record.payload._tag === "ToolCallSettled" && record.payload.runId === runId && record.payload.toolCallId === call.id)?.record.payload;
5192
+ if (calls.length !== 1 || call === void 0 || settled?._tag !== "ToolCallSettled" || settled.toolName !== call.name || settled.isFailure) return yield* RunJournalError.make({ message: `Run ${runId} has a terminal completion marker without one successful declared Tool result` });
5193
+ }
5194
+ return {
5195
+ _tag: "completed",
5196
+ result: recordedCompletion.output,
5197
+ ...recordedCompletion.runDisposition === void 0 ? {} : { runDisposition: recordedCompletion.runDisposition },
5198
+ ...recordedCompletion.finishReason === void 0 ? {} : { finishReason: recordedCompletion.finishReason },
5199
+ ...recordedCompletion.exhausted === void 0 ? {} : { exhausted: recordedCompletion.exhausted },
5200
+ usageSummary: yield* currentUsageSummary()
5201
+ };
5202
+ }
5203
+ let ownerFirstSequence;
5204
+ for (const envelope of records) {
5205
+ const payload = envelope.record.payload;
5206
+ if ("runId" in payload && payload.runId === runId) {
5207
+ ownerFirstSequence = envelope.sequence;
5208
+ break;
5209
+ }
5210
+ }
5211
+ /** Only canonical joined inputs can require restoration from an earlier Attempt. */
5212
+ let joinBacklog = joinedInputEnvelopes.size === 0 ? [] : void 0;
5213
+ /** Joined inputs already handed to the engine during THIS Attempt (never re-deliver). */
5214
+ const deliveredJoinInputs = /* @__PURE__ */ new Set();
5215
+ const encodedParamsByCallId = /* @__PURE__ */ new Map();
5216
+ const declaredNamesByCallId = /* @__PURE__ */ new Map();
5217
+ const subagentState = subagentRecordsOf(records, runId);
5218
+ const declaredToolIds = new Set(subagentState.declaredNames.keys());
5219
+ if (declaredToolIds.size > 4096) return yield* RunJournalError.make({ message: `Run exceeds the ${MAX_RUN_TOOL_CALL_IDENTITIES} Tool Call identity limit` });
5220
+ for (const [callId, name] of subagentState.declaredNames) declaredNamesByCallId.set(callId, name);
5221
+ if (pending !== void 0) for (const call of pending.calls) {
5222
+ encodedParamsByCallId.set(call.id, call.params);
5223
+ declaredNamesByCallId.set(call.id, call.name);
5224
+ }
5225
+ let resumeLeadingMessages;
5226
+ let resumeResponseMessages;
5227
+ if (pending !== void 0) {
5228
+ const pendingMessages = yield* decodePrompt(pending.messages).pipe(Effect.mapError((cause) => RunJournalError.make({
5229
+ message: "Pending ModelResponseRecorded messages are not Schema-encoded Prompt messages",
5230
+ cause
5231
+ })));
5232
+ const firstAssistant = pendingMessages.content.findIndex((message) => message.role === "assistant");
5233
+ if (firstAssistant > 0) resumeLeadingMessages = Prompt.fromMessages(pendingMessages.content.slice(0, firstAssistant).filter((message) => message.role !== "system"));
5234
+ if (firstAssistant >= 0) resumeResponseMessages = Prompt.fromMessages(pendingMessages.content.slice(firstAssistant));
5235
+ }
5236
+ const initialDispatchProofTurns = new Set(initialDispatchBlockedTurns(records, runId));
5237
+ let currentToolTurn = pending === void 0 ? void 0 : {
5238
+ turn: pending.turn,
5239
+ turnId: pending.turnId
5240
+ };
5241
+ const haltRef = yield* Ref.make(void 0);
5242
+ const yieldSignal = yield* Deferred.make();
5243
+ const recordHalt = (effect) => Effect.catchCause(effect, (cause) => {
5244
+ const first = Cause.findErrorOption(cause);
5245
+ const failure = Effect.failCause(Cause.map(cause, (error) => error instanceof ThreadStoreError && error.cause instanceof AgentPersistenceCapacityError ? error.cause : new CoordinatorHalt(error)));
5246
+ return Option.isNone(first) || first.value instanceof ThreadStoreError && first.value.cause instanceof AgentPersistenceCapacityError ? failure : Effect.andThen(Ref.set(haltRef, first.value), failure);
5247
+ });
5248
+ const progress = progressWriters.get(ctx);
5249
+ const checkProgress = progress === void 0 ? Effect.void : progress.check(runId).pipe(Effect.provideService(CurrentRunWriter, ctx));
5250
+ const checkpoint = recordHalt(Effect.flatMap(Ref.get(haltRef), (failure) => failure === void 0 ? checkProgress : Effect.fail(failure)));
5251
+ const responseGate = yield* Semaphore.make(1);
5252
+ let deferredResponse;
5253
+ const acceptResponseDeclarations = (batch) => {
5254
+ for (const record of batch.records) {
5255
+ if (record.payload._tag !== "ModelResponseRecorded") continue;
5256
+ for (const call of record.payload.toolOperations) {
5257
+ declaredToolIds.add(call.toolCallId);
5258
+ declaredNamesByCallId.set(call.toolCallId, call.toolName);
5259
+ }
5260
+ }
5261
+ };
5262
+ const promoteResponse = Effect.gen(function* () {
5263
+ const halted = yield* Ref.get(haltRef);
5264
+ if (halted !== void 0) return yield* halted;
5265
+ const deferred = deferredResponse;
5266
+ if (deferred === void 0) return;
5267
+ const record = deferred.batch.records[0];
5268
+ if (record?.payload._tag !== "ModelResponseRecorded") return yield* RunJournalError.make({ message: "Deferred Turn has no owned response" });
5269
+ const calls = yield* declaredToolCalls(record.payload.messages);
5368
5270
  const batch = CanonicalBatch.make({
5369
- batchId: decodeBatchIdSync(recordId),
5370
- producerId: config.producerId,
5371
- records: [record]
5271
+ ...deferred.batch,
5272
+ batchId: turnResponseBatchId(runId, deferred.turn)
5372
5273
  });
5373
5274
  yield* appendBatch(ctx, batch);
5275
+ acceptResponseDeclarations(batch);
5276
+ for (const call of calls.application) encodedParamsByCallId.set(call.id, call.params);
5374
5277
  recordCommittedUsage(batch);
5375
- knownIds.add(recordId);
5376
- })),
5377
- reservePolicyUsage: (usage) => recordHalt(Effect.gen(function* () {
5378
- yield* flushDeferredResponse;
5379
- const recordId = decodeRecordIdSync(`policy:${runId}:${usage.programmaticToolCalls}:${usage.finalizationUsed}`);
5380
- if (knownIds.has(recordId)) return;
5381
- const record = yield* makeEnvelope(recordId, RunPolicyUsageReserved.make({
5382
- runId,
5383
- ...usage
5384
- }));
5385
- yield* hit("policy:before-reservation-append");
5386
- yield* appendBatch(ctx, CanonicalBatch.make({
5387
- batchId: decodeBatchIdSync(recordId),
5388
- producerId: config.producerId,
5389
- records: [record]
5390
- }));
5391
- knownIds.add(recordId);
5392
- yield* hit("policy:after-reservation-append");
5393
- })),
5394
- commitTurn: (commit) => recordHalt(Effect.gen(function* () {
5395
- const halted = yield* Ref.get(haltRef);
5396
- if (halted !== void 0) return yield* halted;
5397
- if (deferredResponse !== void 0 && (deferredResponse.turn !== commit.turn || deferredResponse.turnId !== commit.turnId)) return yield* RunJournalError.make({ message: "A new Turn preceded settlement of its deferred response" });
5398
- if (commit._tag === "Partial") yield* promoteResponse;
5399
- const deferred = deferredResponse;
5400
- if (commit._tag === "Response" && deferred !== void 0) return yield* RunJournalError.make({ message: "Turn response was already deferred" });
5401
- const responseId = modelResponseRecordId(runId, commit.turn);
5402
- const suppliedResponse = commit._tag === "Partial" ? void 0 : commit.response;
5403
- const response = knownIds.has(responseId) || deferred !== void 0 ? void 0 : suppliedResponse;
5404
- if (suppliedResponse !== void 0) currentToolTurn = {
5405
- turn: commit.turn,
5406
- turnId: commit.turnId
5407
- };
5408
- if (commit._tag === "Response" && response === void 0) return "committed";
5409
- const toolOperations = [];
5410
- const responseToolIds = /* @__PURE__ */ new Set();
5411
- for (const call of response?.calls ?? []) {
5412
- if (declaredToolIds.has(call.toolCallId) || responseToolIds.has(call.toolCallId)) return yield* RunJournalError.make({ message: "Tool Call identity is reused within a Run" });
5413
- if (declaredToolIds.size + responseToolIds.size + 1 > 4096) return yield* RunJournalError.make({ message: `Run exceeds the ${MAX_RUN_TOOL_CALL_IDENTITIES} Tool Call identity limit` });
5414
- const replay = currentContracts[call.toolName];
5415
- if (replay === void 0) return yield* RunJournalError.make({ message: "Canonical Tool declaration has no original operation contract" });
5416
- toolOperations.push(ToolOperation.make({
5417
- toolCallId: call.toolCallId,
5418
- toolName: call.toolName,
5419
- executionClass: call.executionClass,
5420
- executionKind: call.executionKind,
5421
- replay
5422
- }));
5423
- responseToolIds.add(call.toolCallId);
5278
+ for (const entry of batch.records) knownIds.add(entry.recordId);
5279
+ deferredResponse = void 0;
5280
+ yield* hit("turn:after-response-append");
5281
+ });
5282
+ const flushDeferredResponse = promoteResponse.pipe(Effect.tapError((failure) => failure instanceof ThreadStoreError && failure.cause instanceof AgentPersistenceCapacityError ? Effect.void : Ref.set(haltRef, failure)), responseGate.withPermits(1));
5283
+ let initialHistoryLength = 0;
5284
+ let initialInstructions = [];
5285
+ const completionState = {};
5286
+ const turnCounter = yield* Ref.make(journal.committedTurns + (journal.policyUsage.modelRestarts ?? 0));
5287
+ const idGenerator = {
5288
+ nextThreadId: Effect.succeed(submission.threadId),
5289
+ nextRunId: Effect.succeed(runId),
5290
+ nextTurnId: Ref.modify(turnCounter, (turn) => [turnIdForRun(runId, turn + 1), turn + 1])
5291
+ };
5292
+ const instructionView = (messages, instructions, insertWhenAbsent, priorRunPrefixLength) => {
5293
+ const projected = [];
5294
+ const lengths = [0];
5295
+ let inserted = false;
5296
+ for (const [index, message] of messages.entries()) {
5297
+ if (index >= priorRunPrefixLength && message.role === "system") {
5298
+ if (!inserted) projected.push(...instructions);
5299
+ inserted = true;
5300
+ } else projected.push(message);
5301
+ lengths.push(projected.length);
5424
5302
  }
5425
- const toolResults = commit._tag === "Response" ? [] : commit.results.filter((result) => !knownIds.has(toolCallSettledRecordId(runId, commit.turn, result.toolCallId)));
5426
- let runCompletion;
5427
- if (commit._tag === "Settled" && commit.completion !== void 0) {
5428
- const completion = commit.completion;
5429
- const output = yield* decodePersisted(completion.output).pipe(Effect.mapError((cause) => LedgerError.make({
5430
- operation: "recordCompleted",
5431
- message: "Run output exceeds canonical persistence bounds",
5303
+ if (!inserted && insertWhenAbsent) projected.push(...instructions);
5304
+ return {
5305
+ messages: projected,
5306
+ prefixLength: (length) => lengths[length] ?? projected.length
5307
+ };
5308
+ };
5309
+ const resumeContext = { prepare: ({ source }) => Effect.sync(() => {
5310
+ const prefix = journal.committedTurns === 0 && priorContext !== void 0 ? priorContext.prompt.content.slice(priorContext.priorHistoryLength) : [];
5311
+ const priorRunPrefixLength = journal.committedTurns === 0 ? resumeProjection.prompt.content.length : resumeProjection.historyBefore.content.length;
5312
+ const view = instructionView(prefix.length === 0 ? resumeProjection.prompt.content : [...resumeProjection.prompt.content, ...prefix], initialInstructions, true, priorRunPrefixLength);
5313
+ return {
5314
+ prompt: Prompt.fromMessages([...view.messages, ...source.content.slice(initialHistoryLength)]),
5315
+ priorRunPrefixLength: view.prefixLength(priorRunPrefixLength)
5316
+ };
5317
+ }) };
5318
+ const externalContext = runContextPreparation.hook;
5319
+ const needsContextReplay = priorContext !== void 0 || journal.committedTurns > 0;
5320
+ const preparedContext = externalContext === void 0 ? needsContextReplay ? resumeContext : void 0 : { prepare: (request) => (needsContextReplay ? resumeContext.prepare(request) : Effect.succeed({
5321
+ prompt: request.source,
5322
+ priorRunPrefixLength: journal.historyBefore.content.length
5323
+ })).pipe(Effect.flatMap(({ prompt, priorRunPrefixLength }) => externalContext.prepare({
5324
+ ...request,
5325
+ source: prompt,
5326
+ priorRunPrefixLength
5327
+ })), Effect.map((prepared) => {
5328
+ if (prepared.rollover === void 0 || !knownIds.has(compactionRecordId(runId, request.turn, "rollover"))) return prepared;
5329
+ const { rollover: _, ...retained } = prepared;
5330
+ return retained;
5331
+ })) };
5332
+ const durability = {
5333
+ toolResultMaxBytes: MAX_PERSISTED_JSON_BYTES,
5334
+ checkpoint,
5335
+ initialize: ({ initialHistory, priorHistoryLength }) => recordHalt(Effect.gen(function* () {
5336
+ initialHistoryLength = initialHistory.content.length;
5337
+ initialInstructions = initialHistory.content.slice(priorHistoryLength).filter((message) => message.role === "system");
5338
+ if (priorContext !== void 0) return;
5339
+ const recordId = decodeRecordIdSync(JSON.stringify(["run-context@1", runId]));
5340
+ const prompt = yield* Schema.encodeEffect(Prompt.Prompt)(Prompt.fromMessages(initialHistory.content.slice(priorHistoryLength))).pipe(Effect.flatMap(decodePersisted), Effect.mapError((cause) => RunJournalError.make({
5341
+ message: "Original Run context exceeds persistence bounds",
5432
5342
  cause
5433
5343
  })));
5434
- if (completion.finishReason === "budget-exhausted" && completion.runDisposition !== void 0) return yield* LedgerError.make({
5435
- operation: "recordCompleted",
5436
- message: "A budget-exhausted Run cannot declare an application run disposition"
5437
- });
5438
- const runDisposition = completion.runDisposition === void 0 ? void 0 : yield* decodePersisted(completion.runDisposition).pipe(Effect.mapError((cause) => LedgerError.make({
5439
- operation: "recordCompleted",
5440
- message: "Run disposition exceeds canonical persistence bounds",
5344
+ const history = Prompt.fromMessages(initialHistory.content.slice(0, priorHistoryLength));
5345
+ const historyDigest = yield* withCrypto(digestPromptHistory(history, initialJournal?.history));
5346
+ const retained = yield* Effect.forEach([...historyEvidence.values()].filter((entry) => entry.sequence < journal.historyFrom).sort((left, right) => left.sequence - right.sequence), (entry) => Effect.gen(function* () {
5347
+ const full = yield* getRecord({
5348
+ threadId: ctx.threadId,
5349
+ recordId: entry.record.recordId
5350
+ });
5351
+ if (Option.isNone(full) || full.value.sequence !== entry.sequence) return yield* RunJournalError.make({ message: "Retained history has no exact canonical fact" });
5352
+ return {
5353
+ ...yield* withCrypto(reference(full.value.record)),
5354
+ sequence: entry.sequence
5355
+ };
5356
+ }).pipe(Effect.provideService(ThreadReader, reader)));
5357
+ const payload = yield* RunContextRecorded.makeEffect({
5358
+ version: 1,
5359
+ runId,
5360
+ runScopedInput: prompt,
5361
+ historyFrom: journal.historyFrom,
5362
+ historyThrough: CanonicalSequence.make(originalInput.sequence - 1),
5363
+ retained,
5364
+ historyDigest,
5365
+ priorHistoryLength,
5366
+ ...journal.contextWindowId === void 0 ? {} : { contextWindowId: journal.contextWindowId }
5367
+ }).pipe(Effect.mapError((cause) => RunJournalError.make({
5368
+ message: "Original Run context mapping exceeds its bounds",
5441
5369
  cause
5442
5370
  })));
5443
- runCompletion = {
5444
- output,
5445
- ...runDisposition === void 0 ? {} : { runDisposition },
5446
- ...completion.finishReason === "budget-exhausted" ? {
5447
- finishReason: completion.finishReason,
5448
- ...completion.exhausted === void 0 ? {} : { exhausted: completion.exhausted }
5449
- } : {}
5450
- };
5451
- }
5452
- if (response === void 0 && deferred === void 0 && toolResults.length === 0 && runCompletion === void 0) return "committed";
5453
- if (response === void 0 && deferred === void 0 && !knownIds.has(responseId)) return yield* RunJournalError.make({ message: "Tool results or completion preceded the canonical response" });
5454
- const input = {
5455
- toolResultMaxBytes: Math.min(agent.definition.policy.toolResultBounds.maxBytes, MAX_PERSISTED_JSON_BYTES),
5456
- toolSelectionMaxBytes: utf8ByteLength(JSON.stringify({ toolSelection: { toolNames: Object.keys(currentContracts) } })),
5457
- runId,
5458
- turn: commit.turn,
5459
- turnId: commit.turnId,
5460
- responseMessages: response?.messages ?? [],
5461
- toolResults,
5462
- toolOperations,
5463
- toolExposure: response?.toolExposure,
5464
- toolParameterRejections: response?.toolParameterRejections,
5465
- runScopedPrefixLength: response?.runScopedPrefixLength,
5466
- producerId: config.producerId,
5467
- deploymentId: config.deploymentId,
5468
- createdAt: yield* nowUtc,
5469
- runCompletion,
5470
- usage: usageForCommit(commit.turn),
5471
- unobservedModelCalls: unobservedForCommit(commit.turn)
5472
- };
5473
- if (commit._tag === "Partial") {
5474
- for (const result of toolResults) {
5475
- const batch = yield* withCrypto(turnResultsBatch({
5476
- ...input,
5477
- toolResults: [result]
5478
- }));
5479
- yield* appendBatch(ctx, CanonicalBatch.make({
5480
- ...batch,
5481
- batchId: toolCallResultBatchId(runId, commit.turn, result.toolCallId)
5482
- }));
5483
- for (const record of batch.records) knownIds.add(record.recordId);
5484
- yield* hit("subagent:after-sibling-settle");
5485
- }
5486
- return "committed";
5487
- }
5488
- if (commit._tag === "Response" && commit.defer === true) {
5489
- if (toolOperations.length === 0 || toolOperations.some((call) => call.executionClass !== "readonly" || call.executionKind !== "ordinary")) return yield* RunJournalError.make({ message: "Only ordinary readonly Tool responses may be deferred" });
5490
- const candidate = {
5491
- turn: commit.turn,
5492
- turnId: commit.turnId,
5493
- batch: yield* withCrypto(turnCanonicalBatch({
5494
- ...input,
5495
- toolParameterRejections: input.toolParameterRejections?.map((rejection) => ({
5496
- ...rejection,
5497
- parameters: copyJson(rejection.parameters),
5498
- error: {
5499
- ...rejection.error,
5500
- reason: { ...rejection.error.reason }
5501
- }
5502
- })),
5503
- toolExposure: input.toolExposure === void 0 ? void 0 : Snapshot.make({
5504
- exposedToolNames: [...input.toolExposure.exposedToolNames],
5505
- ...input.toolExposure.selection === void 0 ? {} : { selection: Selection.make({ toolNames: [...input.toolExposure.selection.toolNames] }) }
5506
- }),
5507
- usage: input.usage === void 0 ? void 0 : {
5508
- ...input.usage,
5509
- modelUsage: input.usage.modelUsage?.map((usage) => ModelCallUsage.make({
5510
- ...usage,
5511
- ...usage.response === void 0 ? {} : { response: ModelResponseIdentity.make({ ...usage.response }) },
5512
- inputTokens: InputTokenUsage.make({ ...usage.inputTokens }),
5513
- outputTokens: OutputTokenUsage.make({ ...usage.outputTokens })
5514
- }))
5515
- }
5516
- }))
5517
- };
5518
- const progress = progressWriters.get(ctx);
5519
- if (progress === void 0) return yield* ThreadStoreError.make({
5520
- operation: "reserve readonly dispatch",
5521
- message: "Dispatch has no scoped progress writer"
5522
- });
5523
- const batch = yield* progress.defer(candidate.batch).pipe(Effect.provideService(CurrentRunWriter, ctx));
5524
- deferredResponse = {
5525
- ...candidate,
5526
- batch
5527
- };
5528
- return "deferred";
5529
- }
5530
- let batch;
5531
- if (deferred === void 0) batch = yield* withCrypto(commit._tag === "Response" ? turnResponseBatch(input) : response === void 0 ? turnResultsBatch(input) : turnCanonicalBatch(input));
5532
- else if (toolResults.length === 0 && runCompletion === void 0) batch = deferred.batch;
5533
- else {
5534
- const results = yield* withCrypto(turnResultsBatch(input));
5535
- batch = CanonicalBatch.make({
5536
- ...deferred.batch,
5537
- records: [...deferred.batch.records, ...results.records]
5538
- });
5539
- }
5540
- yield* appendBatch(ctx, batch);
5541
- for (const call of response?.calls ?? []) {
5542
- declaredToolIds.add(call.toolCallId);
5543
- encodedParamsByCallId.set(call.toolCallId, call.parameters);
5544
- declaredNamesByCallId.set(call.toolCallId, call.toolName);
5545
- }
5546
- if (deferred !== void 0) {
5547
- acceptResponseDeclarations(batch);
5548
- deferredResponse = void 0;
5549
- }
5550
- if (commit._tag === "Response") initialDispatchProofTurns.add(commit.turn);
5551
- recordCommittedUsage(batch);
5552
- for (const record of batch.records) knownIds.add(record.recordId);
5553
- if (runCompletion !== void 0) completionState.committed = runCompletion;
5554
- yield* hit(commit._tag === "Response" ? "turn:after-response-append" : response === void 0 && deferred === void 0 ? "turn:after-results-append" : "turn:after-canonical-append");
5555
- return "committed";
5556
- }).pipe(responseGate.withPermits(1))),
5557
- checkToolDispatch: recordHalt(Effect.gen(function* () {
5558
- if (currentToolTurn === void 0) return yield* RunJournalError.make({ message: "Tool dispatch preceded its canonical response" });
5559
- yield* hit("tools:before-dispatch-fence");
5560
- yield* ctx.checkActive;
5561
- initialDispatchProofTurns.delete(currentToolTurn.turn);
5562
- yield* hit("tools:after-dispatch-fence");
5563
- })),
5564
- step: {
5565
- lookup: (key) => recordHalt(Effect.gen(function* () {
5566
- yield* flushDeferredResponse;
5567
- const output = stepOutputs.get(toolStepSettledRecordId(runId, key.toolCallId, key.stepName));
5568
- return output === void 0 ? Option.none() : Option.some({ encodedOutput: output });
5371
+ yield* (yield* CurrentRunStart).commit(yield* makeEnvelope(recordId, payload));
5372
+ knownIds.add(runStartedRecordId(runId));
5373
+ knownIds.add(recordId);
5374
+ historyEvidence.clear();
5375
+ projectedJournal = void 0;
5569
5376
  })),
5570
- reserve: (key) => recordHalt(Effect.gen(function* () {
5571
- yield* flushDeferredResponse;
5572
- const recordId = toolStepSettledRecordId(runId, key.toolCallId, key.stepName);
5573
- const template = yield* makeEnvelope(recordId, yield* ToolStepSettled.makeEffect({
5377
+ commitModelRestart: (restart) => recordHalt(Effect.gen(function* () {
5378
+ if (knownIds.has(modelResponseRecordId(runId, restart.turn))) return yield* RunJournalError.make({ message: "Cannot restart a canonical model response" });
5379
+ const recordId = decodeRecordIdSync(`model-aborted:${runId}:${restart.restart}`);
5380
+ const record = yield* makeEnvelope(recordId, ModelCallAborted.make({
5574
5381
  runId,
5575
- toolCallId: key.toolCallId,
5576
- stepName: key.stepName,
5577
- output: null,
5578
- outputDigest: yield* withCrypto(digestJson(null))
5579
- }).pipe(Effect.mapError(() => ThreadStoreError.make({
5580
- operation: "reserve Step dispatch",
5581
- message: "Durable Step identity exceeds canonical persistence bounds",
5582
- cause: AgentPersistenceCapacityError.make({ message: "Durable Step identity exceeds canonical persistence bounds" })
5583
- }))));
5584
- const progress = progressWriters.get(ctx);
5585
- if (progress === void 0) return yield* ThreadStoreError.make({
5586
- operation: "reserve Step dispatch",
5587
- message: "Dispatch has no scoped progress writer"
5588
- });
5589
- return yield* progress.reserve(runId, CanonicalBatch.make({
5382
+ ...restart,
5383
+ reason: "joined-input",
5384
+ modelUsage: usageForCommit(restart.turn)?.modelUsage ?? [],
5385
+ unobservedModelCalls: unobservedForCommit(restart.turn)
5386
+ }));
5387
+ const batch = CanonicalBatch.make({
5590
5388
  batchId: decodeBatchIdSync(recordId),
5591
5389
  producerId: config.producerId,
5592
- records: [template]
5593
- }), canonicalRecordBytes(template) + MAX_PERSISTED_JSON_BYTES + MAX_RUN_CONTINUATION_BYTES).pipe(Effect.provideService(CurrentRunWriter, ctx));
5390
+ records: [record]
5391
+ });
5392
+ yield* appendBatch(ctx, batch);
5393
+ recordCommittedUsage(batch);
5394
+ knownIds.add(recordId);
5594
5395
  })),
5595
- commit: (key, encodedOutput) => recordHalt(Effect.gen(function* () {
5396
+ reservePolicyUsage: (usage) => recordHalt(Effect.gen(function* () {
5596
5397
  yield* flushDeferredResponse;
5597
- const recordId = toolStepSettledRecordId(runId, key.toolCallId, key.stepName);
5398
+ const recordId = decodeRecordIdSync(`policy:${runId}:${usage.programmaticToolCalls}:${usage.finalizationUsed}`);
5598
5399
  if (knownIds.has(recordId)) return;
5599
- const output = yield* decodePersisted(encodedOutput).pipe(Effect.mapError(() => ThreadStoreError.make({
5600
- operation: "commit Step result",
5601
- message: "Durable Step output exceeds canonical persistence bounds",
5602
- cause: AgentPersistenceCapacityError.make({ message: "Durable Step output exceeds canonical persistence bounds" })
5603
- })));
5604
- const outputDigest = yield* withCrypto(digestJson(output));
5605
- const envelope = yield* makeEnvelope(recordId, ToolStepSettled.make({
5400
+ const record = yield* makeEnvelope(recordId, RunPolicyUsageReserved.make({
5606
5401
  runId,
5607
- toolCallId: key.toolCallId,
5608
- stepName: key.stepName,
5609
- output,
5610
- outputDigest
5402
+ ...usage
5611
5403
  }));
5404
+ yield* hit("policy:before-reservation-append");
5612
5405
  yield* appendBatch(ctx, CanonicalBatch.make({
5613
- batchId: toolStepSettledBatchId(runId, key.toolCallId, key.stepName),
5406
+ batchId: decodeBatchIdSync(recordId),
5614
5407
  producerId: config.producerId,
5615
- records: [envelope]
5408
+ records: [record]
5616
5409
  }));
5617
5410
  knownIds.add(recordId);
5618
- stepOutputs.set(recordId, output);
5619
- yield* hit("step:after-step-append");
5620
- }))
5621
- },
5622
- noteTurnUsage: (usage) => Effect.sync(() => {
5623
- const key = usage.turn;
5624
- const prior = stagedUsage.get(key);
5625
- stagedUsage.set(key, {
5626
- inputTokens: (prior?.inputTokens ?? 0) + usage.usage.inputTokens.total,
5627
- outputTokens: (prior?.outputTokens ?? 0) + usage.usage.outputTokens.total,
5628
- costMicrousd: (prior?.costMicrousd ?? 0) + usage.usage.costMicrousd,
5629
- modelUsage: [...prior?.modelUsage ?? [], usage.usage]
5630
- });
5631
- progressWriters.get(ctx)?.stageUsage(runId, terminalUsageCharge(uncommittedModelUsage()));
5632
- }),
5633
- commitCompaction: (commit) => Effect.gen(function* () {
5634
- const canonicalTurn = commit.turn;
5635
- const recordId = compactionRecordId(runId, canonicalTurn, commit.kind);
5636
- if (knownIds.has(recordId)) return yield* CompactionError.make({ message: "Compaction is already committed for this Turn and kind" });
5637
- let sourceJournal = journal;
5638
- let sourceBoundaries = boundaries;
5639
- if (initialJournal !== void 0) {
5640
- initialJournal.cacheable = false;
5641
- initialJournal.history = void 0;
5642
- }
5643
- if (commit.kind !== "summarize" || initialJournal?.prefix !== void 0) {
5644
- const tail = yield* ctx.tail;
5645
- const source = initialJournal === void 0 ? canonical : Stream.fromIterable(yield* recordHalt(readInitialJournal(initialJournal.original, initialJournal.suffix)));
5646
- sourceBoundaries = [];
5647
- sourceJournal = yield* recordHalt(projectRunJournalStream(Stream.concat(source, Stream.fromIterable(yield* recordHalt(selectedRange(ctx.threadId, [submissionId], tail.sequence, canonicalThrough)))).pipe(Stream.filter((envelope) => envelope.record.payload._tag !== "CompactionCreated" || envelope.sequence <= canonicalThrough)), runId, (boundary) => sourceBoundaries.push(boundary), priorContext));
5648
- }
5649
- const coverable = sourceBoundaries.filter((boundary) => commit.kind !== "summarize" || ownerFirstSequence === void 0 || boundary.sequence < ownerFirstSequence);
5650
- if (coverable.length === 0) return yield* CompactionError.make({ message: commit.kind === "rollover" ? "Durable rollover requires complete canonical records" : "Durable compaction requires eligible canonical records" });
5651
- const comparisonView = instructionView(sourceJournal.prompt.content, initialInstructions, false, sourceJournal.historyBefore.content.length);
5652
- let matchingPrefix = 0;
5653
- let requiredThrough = 0;
5654
- const comparisonLimit = Math.min(comparisonView.messages.length, commit.through);
5655
- for (let index = 0; index < commit.through; index += 1) {
5656
- const message = commit.source.content[index];
5657
- if (message !== void 0 && (commit.kind === "clear-tool-results" ? message.role === "tool" : message.role !== "system")) requiredThrough = index + 1;
5658
- if (index >= comparisonLimit || index !== matchingPrefix || message === void 0) continue;
5659
- const canonicalMessage = comparisonView.messages[index];
5660
- if (canonicalMessage === void 0) continue;
5661
- const encode = (entry) => encodeCompactionMessageJson(entry).pipe(Effect.flatMap(decodeCompactionMessageJson), Effect.map(canonicalJson), Effect.mapError((cause) => CompactionError.make({
5662
- message: "Could not encode the canonical compaction prefix",
5411
+ yield* hit("policy:after-reservation-append");
5412
+ })),
5413
+ commitTurn: (commit) => recordHalt(Effect.gen(function* () {
5414
+ const halted = yield* Ref.get(haltRef);
5415
+ if (halted !== void 0) return yield* halted;
5416
+ if (deferredResponse !== void 0 && (deferredResponse.turn !== commit.turn || deferredResponse.turnId !== commit.turnId)) return yield* RunJournalError.make({ message: "A new Turn preceded settlement of its deferred response" });
5417
+ if (commit._tag === "Partial") yield* promoteResponse;
5418
+ const deferred = deferredResponse;
5419
+ if (commit._tag === "Response" && deferred !== void 0) return yield* RunJournalError.make({ message: "Turn response was already deferred" });
5420
+ const responseId = modelResponseRecordId(runId, commit.turn);
5421
+ const suppliedResponse = commit._tag === "Partial" ? void 0 : commit.response;
5422
+ const response = knownIds.has(responseId) || deferred !== void 0 ? void 0 : suppliedResponse;
5423
+ if (suppliedResponse !== void 0) currentToolTurn = {
5424
+ turn: commit.turn,
5425
+ turnId: commit.turnId
5426
+ };
5427
+ if (commit._tag === "Response" && response === void 0) return "committed";
5428
+ const toolOperations = [];
5429
+ const responseToolIds = /* @__PURE__ */ new Set();
5430
+ for (const call of response?.calls ?? []) {
5431
+ if (declaredToolIds.has(call.toolCallId) || responseToolIds.has(call.toolCallId)) return yield* RunJournalError.make({ message: "Tool Call identity is reused within a Run" });
5432
+ if (declaredToolIds.size + responseToolIds.size + 1 > 4096) return yield* RunJournalError.make({ message: `Run exceeds the ${MAX_RUN_TOOL_CALL_IDENTITIES} Tool Call identity limit` });
5433
+ const replay = currentContracts[call.toolName];
5434
+ if (replay === void 0) return yield* RunJournalError.make({ message: "Canonical Tool declaration has no original operation contract" });
5435
+ toolOperations.push(ToolOperation.make({
5436
+ toolCallId: call.toolCallId,
5437
+ toolName: call.toolName,
5438
+ executionClass: call.executionClass,
5439
+ executionKind: call.executionKind,
5440
+ replay
5441
+ }));
5442
+ responseToolIds.add(call.toolCallId);
5443
+ }
5444
+ const toolResults = commit._tag === "Response" ? [] : commit.results.filter((result) => !knownIds.has(toolCallSettledRecordId(runId, commit.turn, result.toolCallId)));
5445
+ let runCompletion;
5446
+ if (commit._tag === "Settled" && commit.completion !== void 0) {
5447
+ const completion = commit.completion;
5448
+ const output = yield* decodePersisted(completion.output).pipe(Effect.mapError((cause) => LedgerError.make({
5449
+ operation: "recordCompleted",
5450
+ message: "Run output exceeds canonical persistence bounds",
5451
+ cause
5452
+ })));
5453
+ if (completion.finishReason === "budget-exhausted" && completion.runDisposition !== void 0) return yield* LedgerError.make({
5454
+ operation: "recordCompleted",
5455
+ message: "A budget-exhausted Run cannot declare an application run disposition"
5456
+ });
5457
+ const runDisposition = completion.runDisposition === void 0 ? void 0 : yield* decodePersisted(completion.runDisposition).pipe(Effect.mapError((cause) => LedgerError.make({
5458
+ operation: "recordCompleted",
5459
+ message: "Run disposition exceeds canonical persistence bounds",
5460
+ cause
5461
+ })));
5462
+ runCompletion = {
5463
+ output,
5464
+ ...runDisposition === void 0 ? {} : { runDisposition },
5465
+ ...completion.finishReason === "budget-exhausted" ? {
5466
+ finishReason: completion.finishReason,
5467
+ ...completion.exhausted === void 0 ? {} : { exhausted: completion.exhausted }
5468
+ } : {}
5469
+ };
5470
+ }
5471
+ if (response === void 0 && deferred === void 0 && toolResults.length === 0 && runCompletion === void 0) return "committed";
5472
+ if (response === void 0 && deferred === void 0 && !knownIds.has(responseId)) return yield* RunJournalError.make({ message: "Tool results or completion preceded the canonical response" });
5473
+ const input = {
5474
+ toolResultMaxBytes: Math.min(agent.definition.policy.toolResultBounds.maxBytes, MAX_PERSISTED_JSON_BYTES),
5475
+ toolSelectionMaxBytes: utf8ByteLength(JSON.stringify({ toolSelection: { toolNames: Object.keys(currentContracts) } })),
5476
+ runId,
5477
+ turn: commit.turn,
5478
+ turnId: commit.turnId,
5479
+ responseMessages: response?.messages ?? [],
5480
+ toolResults,
5481
+ toolOperations,
5482
+ toolExposure: response?.toolExposure,
5483
+ toolParameterRejections: response?.toolParameterRejections,
5484
+ runScopedPrefixLength: response?.runScopedPrefixLength,
5485
+ producerId: config.producerId,
5486
+ deploymentId: config.deploymentId,
5487
+ createdAt: yield* nowUtc,
5488
+ runCompletion,
5489
+ usage: usageForCommit(commit.turn),
5490
+ unobservedModelCalls: unobservedForCommit(commit.turn)
5491
+ };
5492
+ if (commit._tag === "Partial") {
5493
+ for (const result of toolResults) {
5494
+ const batch = yield* turnResultsBatch({
5495
+ ...input,
5496
+ toolResults: [result]
5497
+ });
5498
+ yield* appendBatch(ctx, CanonicalBatch.make({
5499
+ ...batch,
5500
+ batchId: toolCallResultBatchId(runId, commit.turn, result.toolCallId)
5501
+ }));
5502
+ for (const record of batch.records) knownIds.add(record.recordId);
5503
+ yield* hit("subagent:after-sibling-settle");
5504
+ }
5505
+ return "committed";
5506
+ }
5507
+ if (commit._tag === "Response" && commit.defer === true) {
5508
+ if (toolOperations.length === 0 || toolOperations.some((call) => call.executionClass !== "readonly" || call.executionKind !== "ordinary")) return yield* RunJournalError.make({ message: "Only ordinary readonly Tool responses may be deferred" });
5509
+ const candidate = {
5510
+ turn: commit.turn,
5511
+ turnId: commit.turnId,
5512
+ batch: yield* turnCanonicalBatch({
5513
+ ...input,
5514
+ toolParameterRejections: input.toolParameterRejections?.map((rejection) => ({
5515
+ ...rejection,
5516
+ parameters: copyJson(rejection.parameters),
5517
+ error: {
5518
+ ...rejection.error,
5519
+ reason: { ...rejection.error.reason }
5520
+ }
5521
+ })),
5522
+ toolExposure: input.toolExposure === void 0 ? void 0 : Snapshot.make({
5523
+ exposedToolNames: [...input.toolExposure.exposedToolNames],
5524
+ ...input.toolExposure.selection === void 0 ? {} : { selection: Selection.make({ toolNames: [...input.toolExposure.selection.toolNames] }) }
5525
+ }),
5526
+ usage: input.usage === void 0 ? void 0 : {
5527
+ ...input.usage,
5528
+ modelUsage: input.usage.modelUsage?.map((usage) => ModelCallUsage.make({
5529
+ ...usage,
5530
+ ...usage.response === void 0 ? {} : { response: ModelResponseIdentity.make({ ...usage.response }) },
5531
+ inputTokens: InputTokenUsage.make({ ...usage.inputTokens }),
5532
+ outputTokens: OutputTokenUsage.make({ ...usage.outputTokens })
5533
+ }))
5534
+ }
5535
+ })
5536
+ };
5537
+ const progress = progressWriters.get(ctx);
5538
+ if (progress === void 0) return yield* ThreadStoreError.make({
5539
+ operation: "reserve readonly dispatch",
5540
+ message: "Dispatch has no scoped progress writer"
5541
+ });
5542
+ const batch = yield* progress.defer(candidate.batch).pipe(Effect.provideService(CurrentRunWriter, ctx));
5543
+ deferredResponse = {
5544
+ ...candidate,
5545
+ batch
5546
+ };
5547
+ return "deferred";
5548
+ }
5549
+ let batch;
5550
+ if (deferred === void 0) batch = yield* commit._tag === "Response" ? turnResponseBatch(input) : response === void 0 ? turnResultsBatch(input) : turnCanonicalBatch(input);
5551
+ else if (toolResults.length === 0 && runCompletion === void 0) batch = deferred.batch;
5552
+ else {
5553
+ const results = yield* turnResultsBatch(input);
5554
+ batch = CanonicalBatch.make({
5555
+ ...deferred.batch,
5556
+ records: [...deferred.batch.records, ...results.records]
5557
+ });
5558
+ }
5559
+ yield* appendBatch(ctx, batch);
5560
+ for (const call of response?.calls ?? []) {
5561
+ declaredToolIds.add(call.toolCallId);
5562
+ encodedParamsByCallId.set(call.toolCallId, call.parameters);
5563
+ declaredNamesByCallId.set(call.toolCallId, call.toolName);
5564
+ }
5565
+ if (deferred !== void 0) {
5566
+ acceptResponseDeclarations(batch);
5567
+ deferredResponse = void 0;
5568
+ }
5569
+ if (commit._tag === "Response") initialDispatchProofTurns.add(commit.turn);
5570
+ recordCommittedUsage(batch);
5571
+ for (const record of batch.records) knownIds.add(record.recordId);
5572
+ if (runCompletion !== void 0) completionState.committed = runCompletion;
5573
+ yield* hit(commit._tag === "Response" ? "turn:after-response-append" : response === void 0 && deferred === void 0 ? "turn:after-results-append" : "turn:after-canonical-append");
5574
+ return "committed";
5575
+ }).pipe(responseGate.withPermits(1))),
5576
+ checkToolDispatch: recordHalt(Effect.gen(function* () {
5577
+ if (currentToolTurn === void 0) return yield* RunJournalError.make({ message: "Tool dispatch preceded its canonical response" });
5578
+ yield* hit("tools:before-dispatch-fence");
5579
+ yield* ctx.checkActive;
5580
+ initialDispatchProofTurns.delete(currentToolTurn.turn);
5581
+ yield* hit("tools:after-dispatch-fence");
5582
+ })),
5583
+ step: {
5584
+ lookup: (key) => recordHalt(Effect.gen(function* () {
5585
+ yield* flushDeferredResponse;
5586
+ const output = stepOutputs.get(toolStepSettledRecordId(runId, key.toolCallId, key.stepName));
5587
+ return output === void 0 ? Option.none() : Option.some({ encodedOutput: output });
5588
+ })),
5589
+ reserve: (key) => recordHalt(Effect.gen(function* () {
5590
+ yield* flushDeferredResponse;
5591
+ const recordId = toolStepSettledRecordId(runId, key.toolCallId, key.stepName);
5592
+ const template = yield* makeEnvelope(recordId, yield* ToolStepSettled.makeEffect({
5593
+ runId,
5594
+ toolCallId: key.toolCallId,
5595
+ stepName: key.stepName,
5596
+ output: null,
5597
+ outputDigest: yield* withCrypto(digestJson(null))
5598
+ }).pipe(Effect.mapError(() => ThreadStoreError.make({
5599
+ operation: "reserve Step dispatch",
5600
+ message: "Durable Step identity exceeds canonical persistence bounds",
5601
+ cause: AgentPersistenceCapacityError.make({ message: "Durable Step identity exceeds canonical persistence bounds" })
5602
+ }))));
5603
+ const progress = progressWriters.get(ctx);
5604
+ if (progress === void 0) return yield* ThreadStoreError.make({
5605
+ operation: "reserve Step dispatch",
5606
+ message: "Dispatch has no scoped progress writer"
5607
+ });
5608
+ return yield* progress.reserve(runId, CanonicalBatch.make({
5609
+ batchId: decodeBatchIdSync(recordId),
5610
+ producerId: config.producerId,
5611
+ records: [template]
5612
+ }), canonicalRecordBytes(template) + MAX_PERSISTED_JSON_BYTES + MAX_RUN_CONTINUATION_BYTES).pipe(Effect.provideService(CurrentRunWriter, ctx));
5613
+ })),
5614
+ commit: (key, encodedOutput) => recordHalt(Effect.gen(function* () {
5615
+ yield* flushDeferredResponse;
5616
+ const recordId = toolStepSettledRecordId(runId, key.toolCallId, key.stepName);
5617
+ if (knownIds.has(recordId)) return;
5618
+ const output = yield* decodePersisted(encodedOutput).pipe(Effect.mapError(() => ThreadStoreError.make({
5619
+ operation: "commit Step result",
5620
+ message: "Durable Step output exceeds canonical persistence bounds",
5621
+ cause: AgentPersistenceCapacityError.make({ message: "Durable Step output exceeds canonical persistence bounds" })
5622
+ })));
5623
+ const outputDigest = yield* withCrypto(digestJson(output));
5624
+ const envelope = yield* makeEnvelope(recordId, ToolStepSettled.make({
5625
+ runId,
5626
+ toolCallId: key.toolCallId,
5627
+ stepName: key.stepName,
5628
+ output,
5629
+ outputDigest
5630
+ }));
5631
+ yield* appendBatch(ctx, CanonicalBatch.make({
5632
+ batchId: toolStepSettledBatchId(runId, key.toolCallId, key.stepName),
5633
+ producerId: config.producerId,
5634
+ records: [envelope]
5635
+ }));
5636
+ knownIds.add(recordId);
5637
+ stepOutputs.set(recordId, output);
5638
+ yield* hit("step:after-step-append");
5639
+ }))
5640
+ },
5641
+ noteTurnUsage: (usage) => Effect.sync(() => {
5642
+ const key = usage.turn;
5643
+ const prior = stagedUsage.get(key);
5644
+ stagedUsage.set(key, {
5645
+ inputTokens: (prior?.inputTokens ?? 0) + usage.usage.inputTokens.total,
5646
+ outputTokens: (prior?.outputTokens ?? 0) + usage.usage.outputTokens.total,
5647
+ costMicrousd: (prior?.costMicrousd ?? 0) + usage.usage.costMicrousd,
5648
+ modelUsage: [...prior?.modelUsage ?? [], usage.usage]
5649
+ });
5650
+ progressWriters.get(ctx)?.stageUsage(runId, terminalUsageCharge(uncommittedModelUsage()));
5651
+ }),
5652
+ commitCompaction: Effect.fnUntraced(function* (commit) {
5653
+ const canonicalTurn = commit.turn;
5654
+ const recordId = compactionRecordId(runId, canonicalTurn, commit.kind);
5655
+ if (knownIds.has(recordId)) return yield* CompactionError.make({ message: "Compaction is already committed for this Turn and kind" });
5656
+ let sourceJournal = journal;
5657
+ let sourceBoundaries = boundaries;
5658
+ if (initialJournal !== void 0) {
5659
+ initialJournal.cacheable = false;
5660
+ initialJournal.history = void 0;
5661
+ }
5662
+ if (commit.kind !== "summarize" || initialJournal?.prefix !== void 0) {
5663
+ const tail = yield* ctx.tail;
5664
+ const source = initialJournal === void 0 ? canonical : Stream.fromIterable(yield* recordHalt(readInitialJournal(initialJournal.original, initialJournal.suffix)));
5665
+ sourceBoundaries = [];
5666
+ sourceJournal = yield* recordHalt(projectRunJournalStream(Stream.concat(source, Stream.fromIterable(yield* recordHalt(selectedRange(ctx.threadId, [submissionId], tail.sequence, canonicalThrough)))).pipe(Stream.filter((envelope) => envelope.record.payload._tag !== "CompactionCreated" || envelope.sequence <= canonicalThrough)), runId, (boundary) => sourceBoundaries.push(boundary), priorContext));
5667
+ }
5668
+ const coverable = sourceBoundaries.filter((boundary) => commit.kind !== "summarize" || ownerFirstSequence === void 0 || boundary.sequence < ownerFirstSequence);
5669
+ if (coverable.length === 0) return yield* CompactionError.make({ message: commit.kind === "rollover" ? "Durable rollover requires complete canonical records" : "Durable compaction requires eligible canonical records" });
5670
+ const comparisonView = instructionView(sourceJournal.prompt.content, initialInstructions, false, sourceJournal.historyBefore.content.length);
5671
+ let matchingPrefix = 0;
5672
+ let requiredThrough = 0;
5673
+ const comparisonLimit = Math.min(comparisonView.messages.length, commit.through);
5674
+ for (let index = 0; index < commit.through; index += 1) {
5675
+ const message = commit.source.content[index];
5676
+ if (message !== void 0 && (commit.kind === "clear-tool-results" ? message.role === "tool" : message.role !== "system")) requiredThrough = index + 1;
5677
+ if (index >= comparisonLimit || index !== matchingPrefix || message === void 0) continue;
5678
+ const canonicalMessage = comparisonView.messages[index];
5679
+ if (canonicalMessage === void 0) continue;
5680
+ const encode = (entry) => encodeCompactionMessageJson(entry).pipe(Effect.flatMap(decodeCompactionMessageJson), Effect.map(canonicalJson), Effect.mapError((cause) => CompactionError.make({
5681
+ message: "Could not encode the canonical compaction prefix",
5682
+ cause
5683
+ })));
5684
+ if ((yield* encode(canonicalMessage)) === (yield* encode(message))) matchingPrefix += 1;
5685
+ }
5686
+ let lastCovered;
5687
+ for (let index = 0; index < coverable.length; index += 1) {
5688
+ const candidate = coverable[index];
5689
+ if (candidate === void 0) continue;
5690
+ if (coverable[index + 1]?.tag === "ToolCallSettled") continue;
5691
+ const length = comparisonView.prefixLength(candidate.promptLength);
5692
+ if (length === 0 || length > commit.through) continue;
5693
+ if (length < requiredThrough || length > matchingPrefix) continue;
5694
+ lastCovered = candidate;
5695
+ }
5696
+ if (lastCovered === void 0) return yield* CompactionError.make({ message: commit.kind === "rollover" ? "Rollover coverage cannot be mapped to complete canonical records" : "Compaction coverage cannot be mapped to complete canonical records" });
5697
+ const coveredSequence = lastCovered.sequence;
5698
+ if (commit.kind !== "summarize" && sourceBoundaries.some((boundary) => boundary.incomplete === true && boundary.terminalPriorRun !== true && boundary.sequence <= coveredSequence)) return yield* CompactionError.make({ message: "Compaction cannot cover an incomplete Tool batch" });
5699
+ if (commit.kind === "summarize" && (commit.summary ?? "").trim().length === 0) return yield* CompactionError.make({ message: "A summarize compaction commit carried no summary" });
5700
+ const payload = yield* Schema.decodeEffect(CompactionCreated)({
5701
+ _tag: "CompactionCreated",
5702
+ runId,
5703
+ turn: canonicalTurn,
5704
+ kind: commit.kind,
5705
+ coversThrough: lastCovered.sequence,
5706
+ ...commit.kind === "summarize" ? { summary: commit.summary } : {},
5707
+ ...commit.kind === "rollover" && commit.handoff !== void 0 ? { handoff: commit.handoff } : {}
5708
+ }).pipe(Effect.mapError((cause) => CompactionError.make({
5709
+ message: "Compaction decision exceeds canonical persistence bounds",
5663
5710
  cause
5664
5711
  })));
5665
- if ((yield* encode(canonicalMessage)) === (yield* encode(message))) matchingPrefix += 1;
5666
- }
5667
- let lastCovered;
5668
- for (let index = 0; index < coverable.length; index += 1) {
5669
- const candidate = coverable[index];
5670
- if (candidate === void 0) continue;
5671
- if (coverable[index + 1]?.tag === "ToolCallSettled") continue;
5672
- const length = comparisonView.prefixLength(candidate.promptLength);
5673
- if (length === 0 || length > commit.through) continue;
5674
- if (length < requiredThrough || length > matchingPrefix) continue;
5675
- lastCovered = candidate;
5676
- }
5677
- if (lastCovered === void 0) return yield* CompactionError.make({ message: commit.kind === "rollover" ? "Rollover coverage cannot be mapped to complete canonical records" : "Compaction coverage cannot be mapped to complete canonical records" });
5678
- const coveredSequence = lastCovered.sequence;
5679
- if (commit.kind !== "summarize" && sourceBoundaries.some((boundary) => boundary.incomplete === true && boundary.terminalPriorRun !== true && boundary.sequence <= coveredSequence)) return yield* CompactionError.make({ message: "Compaction cannot cover an incomplete Tool batch" });
5680
- if (commit.kind === "summarize" && (commit.summary ?? "").trim().length === 0) return yield* CompactionError.make({ message: "A summarize compaction commit carried no summary" });
5681
- const payload = yield* Schema.decodeEffect(CompactionCreated)({
5682
- _tag: "CompactionCreated",
5683
- runId,
5684
- turn: canonicalTurn,
5685
- kind: commit.kind,
5686
- coversThrough: lastCovered.sequence,
5687
- ...commit.kind === "summarize" ? { summary: commit.summary } : {},
5688
- ...commit.kind === "rollover" && commit.handoff !== void 0 ? { handoff: commit.handoff } : {}
5689
- }).pipe(Effect.mapError((cause) => CompactionError.make({
5690
- message: "Compaction decision exceeds canonical persistence bounds",
5712
+ const envelope = yield* recordHalt(makeEnvelope(recordId, payload));
5713
+ yield* recordHalt(hit("compaction:before-canonical-append"));
5714
+ yield* recordHalt(appendBatch(ctx, CanonicalBatch.make({
5715
+ batchId: compactionBatchId(runId, canonicalTurn, commit.kind),
5716
+ producerId: config.producerId,
5717
+ records: [envelope]
5718
+ })));
5719
+ knownIds.add(recordId);
5720
+ yield* recordHalt(hit("compaction:after-canonical-append"));
5721
+ })
5722
+ };
5723
+ /** Digest of one declared call's canonical encoded parameters (the original normalized wire). */
5724
+ const approvalParametersDigest = (toolCallId) => Effect.gen(function* () {
5725
+ if (!encodedParamsByCallId.has(toolCallId)) return yield* RunJournalError.make({ message: `Tool Call ${toolCallId} requested approval before its response commit` });
5726
+ const parameters = yield* decodePersisted(encodedParamsByCallId.get(toolCallId)).pipe(Effect.mapError((cause) => RunJournalError.make({
5727
+ message: `Tool Call ${toolCallId} parameters exceed canonical persistence bounds`,
5691
5728
  cause
5692
5729
  })));
5693
- const envelope = yield* recordHalt(makeEnvelope(recordId, payload));
5694
- yield* recordHalt(hit("compaction:before-canonical-append"));
5695
- yield* recordHalt(appendBatch(ctx, CanonicalBatch.make({
5696
- batchId: compactionBatchId(runId, canonicalTurn, commit.kind),
5697
- producerId: config.producerId,
5698
- records: [envelope]
5699
- })));
5700
- knownIds.add(recordId);
5701
- yield* recordHalt(hit("compaction:after-canonical-append"));
5702
- })
5703
- };
5704
- /** Digest of one declared call's canonical encoded parameters (the original normalized wire). */
5705
- const approvalParametersDigest = (toolCallId) => Effect.gen(function* () {
5706
- if (!encodedParamsByCallId.has(toolCallId)) return yield* RunJournalError.make({ message: `Tool Call ${toolCallId} requested approval before its response commit` });
5707
- const parameters = yield* decodePersisted(encodedParamsByCallId.get(toolCallId)).pipe(Effect.mapError((cause) => RunJournalError.make({
5708
- message: `Tool Call ${toolCallId} parameters exceed canonical persistence bounds`,
5709
- cause
5710
- })));
5711
- return yield* withCrypto(digestJson(parameters));
5712
- });
5713
- /**
5714
- * Append the canonical approval records for one declared call: the `ToolApprovalRequested`
5715
- * record — plus the immediate `ToolApprovalDecided` for a policy-auto or intent-backed
5716
- * decision, one atomic batch — or the decision alone when the request is already canonical.
5717
- * Batch identity: the Turn's FIRST canonical approval append owns
5718
- * `turn-approvals:{runId}:{turn}`; later appends of the same Turn (across suspension
5719
- * cycles) use deterministic per-call batches so committed batch content is never
5720
- * contradicted; decision-only appends use `approval-decision:{sid}:{toolCallId}`. Record
5721
- * identity dedupes every replay; an identity conflict means another pass already committed
5722
- * the same records.
5723
- */
5724
- const appendApprovalRecords = (turnInfo, toolCallId, toolName, decided) => Effect.gen(function* () {
5725
- const requestRecordId = toolApprovalRequestRecordId(runId, turnInfo.turn, toolCallId);
5726
- const decisionRecordId = toolApprovalDecisionRecordId(runId, turnInfo.turn, toolCallId);
5727
- const envelopes = [];
5728
- const appendRequest = !knownIds.has(requestRecordId);
5729
- if (appendRequest) {
5730
- const parametersDigest = yield* approvalParametersDigest(toolCallId);
5731
- envelopes.push(yield* makeEnvelope(requestRecordId, ToolApprovalRequested.make({
5732
- blocksInitialDispatch: initialDispatchProofTurns.has(turnInfo.turn),
5730
+ return yield* withCrypto(digestJson(parameters));
5731
+ });
5732
+ /**
5733
+ * Append the canonical approval records for one declared call: the `ToolApprovalRequested`
5734
+ * record — plus the immediate `ToolApprovalDecided` for a policy-auto or intent-backed
5735
+ * decision, one atomic batch — or the decision alone when the request is already canonical.
5736
+ * Batch identity: the Turn's FIRST canonical approval append owns
5737
+ * `turn-approvals:{runId}:{turn}`; later appends of the same Turn (across suspension
5738
+ * cycles) use deterministic per-call batches so committed batch content is never
5739
+ * contradicted; decision-only appends use `approval-decision:{sid}:{toolCallId}`. Record
5740
+ * identity dedupes every replay; an identity conflict means another pass already committed
5741
+ * the same records.
5742
+ */
5743
+ const appendApprovalRecords = (turnInfo, toolCallId, toolName, decided) => Effect.gen(function* () {
5744
+ const requestRecordId = toolApprovalRequestRecordId(runId, turnInfo.turn, toolCallId);
5745
+ const decisionRecordId = toolApprovalDecisionRecordId(runId, turnInfo.turn, toolCallId);
5746
+ const envelopes = [];
5747
+ const appendRequest = !knownIds.has(requestRecordId);
5748
+ if (appendRequest) {
5749
+ const parametersDigest = yield* approvalParametersDigest(toolCallId);
5750
+ envelopes.push(yield* makeEnvelope(requestRecordId, ToolApprovalRequested.make({
5751
+ blocksInitialDispatch: initialDispatchProofTurns.has(turnInfo.turn),
5752
+ runId,
5753
+ turnId: turnInfo.turnId,
5754
+ turn: turnInfo.turn,
5755
+ toolCallId,
5756
+ toolName,
5757
+ parametersDigest
5758
+ })));
5759
+ }
5760
+ if (decided !== void 0 && !knownIds.has(decisionRecordId)) envelopes.push(yield* makeEnvelope(decisionRecordId, ToolApprovalDecided.make({
5733
5761
  runId,
5734
- turnId: turnInfo.turnId,
5735
5762
  turn: turnInfo.turn,
5736
5763
  toolCallId,
5737
- toolName,
5738
- parametersDigest
5764
+ decision: decided.decision,
5765
+ resolver: decided.resolver,
5766
+ reason: decided.reason
5739
5767
  })));
5740
- }
5741
- if (decided !== void 0 && !knownIds.has(decisionRecordId)) envelopes.push(yield* makeEnvelope(decisionRecordId, ToolApprovalDecided.make({
5742
- runId,
5743
- turn: turnInfo.turn,
5744
- toolCallId,
5745
- decision: decided.decision,
5746
- resolver: decided.resolver,
5747
- reason: decided.reason
5748
- })));
5749
- const head = envelopes[0];
5750
- if (head !== void 0) {
5751
- const batchId = appendRequest ? approvalRequestedTurns.has(turnInfo.turn) ? decodeBatchId(`approval-request:${runId}:${turnInfo.turn}:${toolCallId}`) : turnApprovalsBatchId(runId, turnInfo.turn) : approvalDecisionBatchId(submissionId, toolCallId);
5752
- yield* appendBatch(ctx, CanonicalBatch.make({
5753
- batchId,
5754
- producerId: config.producerId,
5755
- records: [head, ...envelopes.slice(1)]
5756
- })).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
5757
- for (const record of envelopes) knownIds.add(record.recordId);
5758
- }
5759
- if (appendRequest) {
5760
- approvalRequestedTurns.add(turnInfo.turn);
5761
- yield* hit("approval:after-request-append");
5762
- }
5763
- if (decided !== void 0) canonicalApprovalDecisions.set(toolCallId, decided.decision);
5764
- });
5765
- /**
5766
- * Retain every required request before any decision can remove initial-dispatch proof.
5767
- * Policy preparation shares the engine deadline; canonical acceptance is a separate,
5768
- * fenced commit. Canonical decisions and accepted resolver intents keep their audit.
5769
- */
5770
- const approval = {
5771
- prepareBatch: (requests) => recordHalt(Effect.gen(function* () {
5772
- if (requests.length === 0) return;
5773
- yield* flushDeferredResponse;
5774
- const turnInfo = currentToolTurn;
5775
- if (turnInfo === void 0) return yield* RunJournalError.make({ message: "Approval preparation preceded its canonical response" });
5776
- for (const request of requests) {
5777
- if (request.threadId !== submission.threadId || request.runId !== runId || request.turnId !== turnInfo.turnId || declaredNamesByCallId.get(request.toolCallId) !== request.toolName) return yield* RunJournalError.make({ message: "Approval preparation does not match its original declaration" });
5778
- yield* appendApprovalRecords(turnInfo, request.toolCallId, request.toolName, void 0);
5779
- }
5780
- })),
5781
- request: (request) => recordHalt(Effect.gen(function* () {
5782
- const canonical = canonicalApprovalDecisions.get(request.toolCallId);
5783
- if (canonical !== void 0) return canonical === "approved" ? { _tag: "approved" } : { _tag: "denied" };
5784
- const intent = approvalIntents.get(request.toolCallId);
5785
- if (intent !== void 0) return intent.decision === "approved" ? {
5786
- _tag: "approved",
5787
- reason: intent.reason
5788
- } : {
5789
- _tag: "denied",
5790
- reason: intent.reason
5791
- };
5792
- return approvalResolver === void 0 ? { _tag: "unresolved" } : yield* approvalResolver.request(request);
5793
- })),
5794
- commit: (request, decision) => recordHalt(Effect.gen(function* () {
5795
- const turnInfo = currentToolTurn;
5796
- if (turnInfo === void 0 || request.threadId !== submission.threadId || request.runId !== runId || request.turnId !== turnInfo.turnId || declaredNamesByCallId.get(request.toolCallId) !== request.toolName) return yield* RunJournalError.make({ message: "Approval acceptance does not match its original declaration" });
5797
- const canonical = canonicalApprovalDecisions.get(request.toolCallId);
5798
- if (canonical !== void 0) {
5799
- if (decision._tag !== canonical) return yield* RunJournalError.make({ message: "Approval preparation disagrees with its canonical decision" });
5800
- return;
5768
+ const head = envelopes[0];
5769
+ if (head !== void 0) {
5770
+ const batchId = appendRequest ? approvalRequestedTurns.has(turnInfo.turn) ? decodeBatchId(`approval-request:${runId}:${turnInfo.turn}:${toolCallId}`) : turnApprovalsBatchId(runId, turnInfo.turn) : approvalDecisionBatchId(submissionId, toolCallId);
5771
+ yield* appendBatch(ctx, CanonicalBatch.make({
5772
+ batchId,
5773
+ producerId: config.producerId,
5774
+ records: [head, ...envelopes.slice(1)]
5775
+ })).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
5776
+ for (const record of envelopes) knownIds.add(record.recordId);
5801
5777
  }
5802
- const intent = approvalIntents.get(request.toolCallId);
5803
- if (intent !== void 0 && decision._tag !== intent.decision) return yield* RunJournalError.make({ message: "Approval preparation disagrees with its accepted intent" });
5804
- yield* appendApprovalRecords(turnInfo, request.toolCallId, request.toolName, intent !== void 0 ? {
5805
- decision: intent.decision,
5806
- resolver: intent.resolver,
5807
- reason: intent.reason
5808
- } : decision._tag === "unresolved" ? void 0 : {
5809
- decision: decision._tag,
5810
- resolver: APPROVAL_POLICY_RESOLVER,
5811
- reason: boundedApprovalReason(decision.reason, "The configured approval policy decided immediately")
5812
- });
5813
- }))
5814
- };
5815
- /**
5816
- * Joining/Joined queued input hook (plan §2.5, DUR-016). At every engine drain seam:
5817
- *
5818
- * 1. Reattach first — pre-existing joins whose canonical `input:{sid}` record is not yet
5819
- * prompt-covered re-deliver WITHOUT re-appending (record identity is the dedupe);
5820
- * covered inputs are already inside the journal prompt. A `joining` row whose input is
5821
- * canonical only lost its marker: it is repaired from history under the host's live
5822
- * ownership (DUR-015). A `joining` row WITHOUT canonical input was never consumed and
5823
- * is recovery's to revert — the hook never guesses at it (fail-closed).
5824
- * 2. Claim fresh — `claimJoining` atomically transitions the contiguous ready prefix of
5825
- * strictly-later queue sequences to `joining` under the host's local generation (an
5826
- * admitted-not-ready row breaks the prefix). Per fresh claim: honor a
5827
- * pre-consumption abort intent by reverting (revert-then-abort), else append the
5828
- * deterministic `UserInputRecorded` (batch `submission-input:{sid}`, record
5829
- * `input:{sid}`, `runId` = host Run, kind `steering`) → `join:after-canonical-append`
5830
- * → `markJoined` → hand the engine the `RunInputCommand`.
5831
- *
5832
- * Delivered input is `steering`: the engine appends it to official history at the seam,
5833
- * so the next Turn's response commit makes it model-visible canonically — exactly the
5834
- * prompt-coverage rule recovery relies on.
5835
- */
5836
- const renderJoinedInput = ({ input: encodedInput, messageAdmission }) => Effect.gen(function* () {
5837
- if (Schema.is(FrameworkMessage)(messageAdmission)) return yield* Schema.encodeEffect(Schema.fromJsonString(FrameworkMessage))(messageAdmission).pipe(Effect.mapError(() => AgentInputError.make({ message: "Invalid worker completion message" })));
5838
- const inputPrompt = agent.definition.inputPrompt;
5839
- if (inputPrompt === void 0) return yield* renderInputPrompt(void 0, encodedInput, encodedInput);
5840
- const decodedInput = yield* Schema.decodeEffect(agent.definition.input)(encodedInput).pipe(Effect.mapError((cause) => AgentInputDecodeError.make({ message: cause.message })));
5841
- return yield* renderInputPrompt(inputPrompt, decodedInput, encodedInput);
5842
- });
5843
- const pendingJoinClaims = [];
5844
- const claimInputs = Effect.fnUntraced(function* (maxCount) {
5845
- const claims = yield* session.claimJoining(maxCount);
5846
- pendingJoinClaims.push(...claims.map((claim) => ({ claim })));
5847
- return claims.length;
5848
- }, Effect.uninterruptible);
5849
- const revertClaims = Effect.fnUntraced(function* (claims) {
5850
- for (const pending of claims) {
5851
- yield* session.revertJoining(pending.claim.submissionId);
5852
- pendingJoinClaims.splice(pendingJoinClaims.indexOf(pending), 1);
5853
- }
5854
- }, Effect.uninterruptible);
5855
- const prepareInputs = Effect.fnUntraced(function* (limit, firstReady = false) {
5856
- if (pendingJoinClaims.length < limit && (yield* claimInputs(limit - pendingJoinClaims.length)) > 0) yield* hit("join:after-claim");
5857
- const prepared = [];
5858
- for (const pending of pendingJoinClaims.slice(0, limit)) {
5859
- const claim = pending.claim;
5860
- const snapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId: claim.submissionId }));
5861
- if (snapshot.abortIntent !== void 0) {
5862
- yield* revertClaims([pending]);
5863
- continue;
5778
+ if (appendRequest) {
5779
+ approvalRequestedTurns.add(turnInfo.turn);
5780
+ yield* hit("approval:after-request-append");
5864
5781
  }
5865
- if (pending.prepared === void 0) {
5866
- const input = {
5867
- input: claim.inputPayload,
5868
- ...snapshot.submission.messageAdmission === void 0 ? {} : { messageAdmission: snapshot.submission.messageAdmission }
5869
- };
5870
- const rendered = yield* Effect.result(renderJoinedInput(input));
5871
- if (Result.isFailure(rendered)) {
5872
- yield* revertClaims(pendingJoinClaims.slice(pendingJoinClaims.indexOf(pending)));
5873
- break;
5782
+ if (decided !== void 0) canonicalApprovalDecisions.set(toolCallId, decided.decision);
5783
+ });
5784
+ /**
5785
+ * Retain every required request before any decision can remove initial-dispatch proof.
5786
+ * Policy preparation shares the engine deadline; canonical acceptance is a separate,
5787
+ * fenced commit. Canonical decisions and accepted resolver intents keep their audit.
5788
+ */
5789
+ const approval = {
5790
+ prepareBatch: (requests) => recordHalt(Effect.gen(function* () {
5791
+ if (requests.length === 0) return;
5792
+ yield* flushDeferredResponse;
5793
+ const turnInfo = currentToolTurn;
5794
+ if (turnInfo === void 0) return yield* RunJournalError.make({ message: "Approval preparation preceded its canonical response" });
5795
+ for (const request of requests) {
5796
+ if (request.threadId !== submission.threadId || request.runId !== runId || request.turnId !== turnInfo.turnId || declaredNamesByCallId.get(request.toolCallId) !== request.toolName) return yield* RunJournalError.make({ message: "Approval preparation does not match its original declaration" });
5797
+ yield* appendApprovalRecords(turnInfo, request.toolCallId, request.toolName, void 0);
5874
5798
  }
5875
- pending.prepared = {
5876
- claim,
5877
- input,
5878
- rendered: rendered.success
5799
+ })),
5800
+ request: (request) => recordHalt(Effect.gen(function* () {
5801
+ const canonical = canonicalApprovalDecisions.get(request.toolCallId);
5802
+ if (canonical !== void 0) return canonical === "approved" ? { _tag: "approved" } : { _tag: "denied" };
5803
+ const intent = approvalIntents.get(request.toolCallId);
5804
+ if (intent !== void 0) return intent.decision === "approved" ? {
5805
+ _tag: "approved",
5806
+ reason: intent.reason
5807
+ } : {
5808
+ _tag: "denied",
5809
+ reason: intent.reason
5879
5810
  };
5811
+ return approvalResolver === void 0 ? { _tag: "unresolved" } : yield* approvalResolver.request(request);
5812
+ })),
5813
+ commit: (request, decision) => recordHalt(Effect.gen(function* () {
5814
+ const turnInfo = currentToolTurn;
5815
+ if (turnInfo === void 0 || request.threadId !== submission.threadId || request.runId !== runId || request.turnId !== turnInfo.turnId || declaredNamesByCallId.get(request.toolCallId) !== request.toolName) return yield* RunJournalError.make({ message: "Approval acceptance does not match its original declaration" });
5816
+ const canonical = canonicalApprovalDecisions.get(request.toolCallId);
5817
+ if (canonical !== void 0) {
5818
+ if (decision._tag !== canonical) return yield* RunJournalError.make({ message: "Approval preparation disagrees with its canonical decision" });
5819
+ return;
5820
+ }
5821
+ const intent = approvalIntents.get(request.toolCallId);
5822
+ if (intent !== void 0 && decision._tag !== intent.decision) return yield* RunJournalError.make({ message: "Approval preparation disagrees with its accepted intent" });
5823
+ yield* appendApprovalRecords(turnInfo, request.toolCallId, request.toolName, intent !== void 0 ? {
5824
+ decision: intent.decision,
5825
+ resolver: intent.resolver,
5826
+ reason: intent.reason
5827
+ } : decision._tag === "unresolved" ? void 0 : {
5828
+ decision: decision._tag,
5829
+ resolver: APPROVAL_POLICY_RESOLVER,
5830
+ reason: boundedApprovalReason(decision.reason, "The configured approval policy decided immediately")
5831
+ });
5832
+ }))
5833
+ };
5834
+ /**
5835
+ * Joining/Joined queued input hook (plan §2.5, DUR-016). At every engine drain seam:
5836
+ *
5837
+ * 1. Reattach first — pre-existing joins whose canonical `input:{sid}` record is not yet
5838
+ * prompt-covered re-deliver WITHOUT re-appending (record identity is the dedupe);
5839
+ * covered inputs are already inside the journal prompt. A `joining` row whose input is
5840
+ * canonical only lost its marker: it is repaired from history under the host's live
5841
+ * ownership (DUR-015). A `joining` row WITHOUT canonical input was never consumed and
5842
+ * is recovery's to revert — the hook never guesses at it (fail-closed).
5843
+ * 2. Claim fresh — `claimJoining` atomically transitions the contiguous ready prefix of
5844
+ * strictly-later queue sequences to `joining` under the host's local generation (an
5845
+ * admitted-not-ready row breaks the prefix). Per fresh claim: honor a
5846
+ * pre-consumption abort intent by reverting (revert-then-abort), else append the
5847
+ * deterministic `UserInputRecorded` (batch `submission-input:{sid}`, record
5848
+ * `input:{sid}`, `runId` = host Run, kind `steering`) → `join:after-canonical-append`
5849
+ * → `markJoined` → hand the engine the `RunInputCommand`.
5850
+ *
5851
+ * Delivered input is `steering`: the engine appends it to official history at the seam,
5852
+ * so the next Turn's response commit makes it model-visible canonically — exactly the
5853
+ * prompt-coverage rule recovery relies on.
5854
+ */
5855
+ const renderJoinedInput = Effect.fnUntraced(function* (encodedInput, messageAdmission) {
5856
+ if (Schema.is(FrameworkMessage)(messageAdmission)) return yield* Schema.encodeEffect(Schema.fromJsonString(FrameworkMessage))(messageAdmission).pipe(Effect.mapError(() => AgentInputError.make({ message: "Invalid worker completion message" })));
5857
+ const inputPrompt = agent.definition.inputPrompt;
5858
+ if (inputPrompt === void 0) return yield* renderInputPrompt(void 0, encodedInput, encodedInput);
5859
+ const decodedInput = yield* Schema.decodeEffect(agent.definition.input)(encodedInput).pipe(Effect.mapError((cause) => AgentInputDecodeError.make({ message: cause.message })));
5860
+ return yield* renderInputPrompt(inputPrompt, decodedInput, encodedInput);
5861
+ });
5862
+ const pendingJoinClaims = [];
5863
+ const claimInputs = Effect.fnUntraced(function* (maxCount) {
5864
+ const claims = yield* session.claimJoining(maxCount);
5865
+ pendingJoinClaims.push(...claims.map((claim) => ({ claim })));
5866
+ return claims.length;
5867
+ }, Effect.uninterruptible);
5868
+ const revertClaims = Effect.fnUntraced(function* (claims) {
5869
+ for (const pending of claims) {
5870
+ yield* session.revertJoining(pending.claim.submissionId);
5871
+ pendingJoinClaims.splice(pendingJoinClaims.indexOf(pending), 1);
5880
5872
  }
5881
- prepared.push(pending.prepared);
5882
- if (firstReady) break;
5883
- }
5884
- return prepared;
5885
- });
5886
- const input = {
5887
- awaitJoin: recordHalt(Effect.gen(function* () {
5888
- while (true) if (yield* Effect.scoped(Effect.gen(function* () {
5889
- const notified = yield* wake.subscribe(submission.threadId);
5890
- if ((yield* prepareInputs(MAX_JOIN_DRAIN, true)).length > 0) return true;
5891
- yield* notified;
5892
- return false;
5893
- }))) return;
5894
- })),
5895
- drain: (policy) => Effect.gen(function* () {
5896
- const joinedInputs = yield* recordHalt(Effect.gen(function* () {
5897
- const limit = policy === "one" ? 1 : MAX_JOIN_DRAIN;
5898
- const joinedInputs = [];
5899
- if (joinBacklog === void 0) joinBacklog = (yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId }))).joins;
5900
- for (const join of joinBacklog) {
5901
- const joinId = join.submissionId;
5902
- if (deliveredJoinInputs.has(joinId)) continue;
5903
- if (join.state !== "joining" && join.state !== "joined") continue;
5904
- const existing = joinedInputEnvelopes.get(joinId);
5905
- if (existing === void 0) continue;
5906
- if (join.state === "joining") yield* session.markJoined(joinId, {
5907
- recordId: existing.record.recordId,
5908
- sequence: existing.sequence
5909
- });
5910
- deliveredJoinInputs.add(joinId);
5911
- if (lastHostResponseSequence !== void 0 && lastHostResponseSequence > existing.sequence) continue;
5912
- const payload = existing.record.payload;
5913
- if (payload._tag !== "UserInputRecorded") continue;
5914
- joinedInputs.push(payload);
5873
+ }, Effect.uninterruptible);
5874
+ const prepareInputs = Effect.fnUntraced(function* (limit, firstReady = false) {
5875
+ if (pendingJoinClaims.length < limit && (yield* claimInputs(limit - pendingJoinClaims.length)) > 0) yield* hit("join:after-claim");
5876
+ const prepared = [];
5877
+ for (const pending of pendingJoinClaims.slice(0, limit)) {
5878
+ const claim = pending.claim;
5879
+ const snapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId: claim.submissionId }));
5880
+ if (snapshot.abortIntent !== void 0) {
5881
+ yield* revertClaims([pending]);
5882
+ continue;
5915
5883
  }
5916
- const claims = yield* prepareInputs(limit);
5917
- pendingJoinClaims.splice(0, claims.length);
5918
- for (const { claim, input: payload, rendered } of claims) {
5919
- const recordId = submissionInputRecordId(claim.submissionId);
5920
- let sequence;
5921
- const existing = joinedInputEnvelopes.get(claim.submissionId);
5922
- if (existing !== void 0) sequence = existing.sequence;
5923
- else {
5924
- const envelope = yield* makeEnvelope(recordId, UserInputRecorded.make({
5925
- submissionId: claim.submissionId,
5926
- kind: "steering",
5927
- runId,
5928
- input: claim.inputPayload,
5929
- ...payload.messageAdmission === void 0 ? {} : { messageAdmission: payload.messageAdmission }
5930
- }));
5931
- sequence = (yield* appendBatch(ctx, CanonicalBatch.make({
5932
- batchId: submissionInputBatchId(claim.submissionId),
5933
- producerId: config.producerId,
5934
- records: [envelope]
5935
- }))).firstSequence;
5936
- knownIds.add(recordId);
5937
- yield* hit("join:after-canonical-append");
5884
+ if (pending.prepared === void 0) {
5885
+ const input = {
5886
+ input: claim.inputPayload,
5887
+ ...snapshot.submission.messageAdmission === void 0 ? {} : { messageAdmission: snapshot.submission.messageAdmission }
5888
+ };
5889
+ const rendered = yield* Effect.result(renderJoinedInput(input.input, input.messageAdmission));
5890
+ if (Result.isFailure(rendered)) {
5891
+ yield* revertClaims(pendingJoinClaims.slice(pendingJoinClaims.indexOf(pending)));
5892
+ break;
5938
5893
  }
5939
- yield* session.markJoined(claim.submissionId, {
5940
- recordId,
5941
- sequence
5942
- });
5943
- deliveredJoinInputs.add(claim.submissionId);
5944
- joinedInputs.push({
5945
- ...payload,
5946
- rendered
5947
- });
5894
+ pending.prepared = {
5895
+ claim,
5896
+ input,
5897
+ rendered: rendered.success
5898
+ };
5948
5899
  }
5949
- return joinedInputs;
5950
- }));
5951
- return yield* Effect.forEach(joinedInputs, (joinedInput) => (joinedInput.rendered === void 0 ? renderJoinedInput(joinedInput) : Effect.succeed(joinedInput.rendered)).pipe(Effect.map((input) => ({
5952
- kind: "steering",
5953
- input
5954
- }))));
5955
- })
5956
- };
5957
- /**
5958
- * Durable child establishment: `establish` performs or replays
5959
- * the idempotent get-or-create establishment protocol under the
5960
- * parent's ownership fence and reports where the one child stands; `join` appends the
5961
- * atomic `[SubagentJoined, ToolCallSettled]` settlement batch (SUB-019) and applies the
5962
- * reservation release. Both use the halt side channel exactly like the durability/step
5963
- * hooks: the engine wraps a `CoordinatorHalt` into `SubagentDurabilityError` in the
5964
- * handler channel while the Attempt aborts with the original infrastructure failure.
5965
- */
5966
- const establishmentGate = yield* Semaphore.make(1);
5967
- const establishSubagent = (request) => recordHalt(Effect.gen(function* () {
5968
- const toolCallId = request.toolCallId;
5969
- const turnInfo = currentToolTurn;
5970
- if (turnInfo === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} established before any canonical response commit` });
5971
- const denied = (errorTag, message) => ({
5972
- _tag: "denied",
5973
- errorTag,
5974
- message: boundedText(message)
5975
- });
5976
- let requestedPayload = subagentState.requested.get(toolCallId);
5977
- if (requestedPayload === void 0) {
5978
- if (request.depth !== delegationDepth + 1) return denied("SubagentDepthUnsupported", `The child depth must be exactly one greater than its source depth ${delegationDepth}`);
5979
- let targetDigests = request.targetDigests;
5980
- if (request.target !== void 0) {
5981
- if (request.target.id !== request.targetAgentId) return denied("SubagentBindingUnavailable", "The child target identity differs from its Definition");
5982
- const binding = yield* resolveDefinitionBinding(registeredBindings, request.target).pipe(Effect.result);
5983
- if (binding._tag === "Failure") return denied("SubagentBindingUnavailable", binding.failure.message);
5984
- if (targetDigests !== void 0 && (targetDigests.agent !== binding.success.digests.agent || targetDigests.model !== binding.success.digests.model || targetDigests.tools !== binding.success.digests.tools)) return denied("SubagentDigestsInvalid", "The explicit child digests differ from its exact registration");
5985
- targetDigests = binding.success.digests;
5900
+ prepared.push(pending.prepared);
5901
+ if (firstReady) break;
5986
5902
  }
5987
- const decodedDigests = yield* decodeDefinitionDigests(targetDigests).pipe(Effect.option);
5988
- if (Option.isNone(decodedDigests)) return denied("SubagentDigestsInvalid", "The declared child Binding digests are not valid stored digests");
5989
- const childInput = yield* decodePersisted(request.encodedChildInput).pipe(Effect.option);
5990
- if (Option.isNone(childInput)) return denied("SubagentInputUnpersistable", "The prepared child input does not satisfy the canonical persistence bounds");
5991
- const grant = yield* decodePersisted(request.encodedGrant).pipe(Effect.option);
5992
- const allocation = yield* decodePersisted(request.encodedAllocation).pipe(Effect.option);
5993
- if (Option.isNone(grant) || Option.isNone(allocation)) return denied("SubagentDeclarationUnpersistable", "The delegation grant or allocation does not satisfy the canonical persistence bounds");
5994
- const decodedGrant = Schema.decodeUnknownOption(SubagentGrant)(grant.value);
5995
- if (Option.isNone(decodedGrant)) return denied("SubagentGrantInvalid", "The child authority grant is invalid");
5996
- if (request.policy === void 0 || request.budget === void 0) return denied("SubagentBudgetInvalid", "New durable children require their full execution policy and subtree allocation");
5997
- if (request.toolCallAllowance !== void 0 && !Schema.is(SubagentRequested.fields.toolCallAllowance)(request.toolCallAllowance)) return denied("SubagentAllowanceInvalid", "The child Tool Call allowance must be a positive integer");
5998
- if (request.policy !== void 0 && !Schema.is(AgentPolicy)(request.policy)) return denied("SubagentPolicyInvalid", "The resolved child policy is invalid");
5999
- if (request.budget !== void 0) {
6000
- if (!Schema.is(SubagentBudgetReservation)(request.budget)) return denied("SubagentBudgetInvalid", "The shared delegation budget is invalid");
6001
- const decodedAllocation = Schema.decodeUnknownOption(SubagentReservationAmounts)(allocation.value);
6002
- if (Option.isNone(decodedAllocation) || !Equal.equals(decodedAllocation.value, request.budget.allocation)) return denied("SubagentBudgetInvalid", "The reserved allocation differs from its budget declaration");
6003
- const { caps, allocation: requested } = request.budget;
6004
- const prior = [...subagentState.requested.values()];
6005
- if (prior.some((entry) => entry.budget === void 0 || !Equal.equals(entry.budget.caps, caps))) return denied("SubagentParentBudgetConflict", "Delegations in one parent Run must share the same caps");
6006
- if (caps.maxTotalChildInvocations !== void 0 && prior.reduce((sum, entry) => sum + 1 + (entry.budget?.descendantInvocations ?? 0), 1 + (request.budget.descendantInvocations ?? 0)) > caps.maxTotalChildInvocations) return denied("SubagentBudgetExhausted", "The parent Run exhausted its child invocation budget");
6007
- const active = prior.filter((entry) => !subagentState.joined.has(entry.toolCallId));
6008
- if (caps.maxConcurrentChildren !== void 0 && active.length >= caps.maxConcurrentChildren) return denied("SubagentBudgetExhausted", "The parent Run exhausted its concurrent child budget");
6009
- const dimensions = [
6010
- ["turns", "maxTurns"],
6011
- ["toolCalls", "maxToolCalls"],
6012
- ["durationMillis", "maxDurationMillis"],
6013
- ["inputTokens", "maxInputTokens"],
6014
- ["outputTokens", "maxOutputTokens"],
6015
- ["costMicrousd", "maxCostMicrousd"],
6016
- ["resultBytes", "maxResultBytes"]
6017
- ];
6018
- const accounting = Schema.Struct({ consumed: SubagentReservationAmounts });
6019
- for (const [amount, cap] of dimensions) {
6020
- const limit = caps[cap];
6021
- if (limit === void 0) continue;
6022
- let consumed = requested[amount];
6023
- for (const entry of prior) {
6024
- const joined = subagentState.joined.get(entry.toolCallId);
6025
- const observed = joined === void 0 ? Option.none() : Schema.decodeUnknownOption(accounting)(joined.finalAccounting);
6026
- consumed += Option.isSome(observed) ? observed.value.consumed[amount] : entry.budget?.allocation[amount] ?? limit;
5903
+ return prepared;
5904
+ });
5905
+ const input = {
5906
+ awaitJoin: recordHalt(Effect.gen(function* () {
5907
+ while (true) if (yield* Effect.scoped(Effect.gen(function* () {
5908
+ const notified = yield* wake.subscribe(submission.threadId);
5909
+ if ((yield* prepareInputs(MAX_JOIN_DRAIN, true)).length > 0) return true;
5910
+ yield* notified;
5911
+ return false;
5912
+ }))) return;
5913
+ })),
5914
+ drain: Effect.fnUntraced(function* (policy) {
5915
+ const joinedInputs = yield* recordHalt(Effect.gen(function* () {
5916
+ const limit = policy === "one" ? 1 : MAX_JOIN_DRAIN;
5917
+ const joinedInputs = [];
5918
+ if (joinBacklog === void 0) joinBacklog = (yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId }))).joins;
5919
+ for (const join of joinBacklog) {
5920
+ const joinId = join.submissionId;
5921
+ if (deliveredJoinInputs.has(joinId)) continue;
5922
+ if (join.state !== "joining" && join.state !== "joined") continue;
5923
+ const existing = joinedInputEnvelopes.get(joinId);
5924
+ if (existing === void 0) continue;
5925
+ if (join.state === "joining") yield* session.markJoined(joinId, {
5926
+ recordId: existing.record.recordId,
5927
+ sequence: existing.sequence
5928
+ });
5929
+ deliveredJoinInputs.add(joinId);
5930
+ if (lastHostResponseSequence !== void 0 && lastHostResponseSequence > existing.sequence) continue;
5931
+ const payload = existing.record.payload;
5932
+ if (payload._tag !== "UserInputRecorded") continue;
5933
+ joinedInputs.push(payload);
5934
+ }
5935
+ const claims = yield* prepareInputs(limit);
5936
+ pendingJoinClaims.splice(0, claims.length);
5937
+ for (const { claim, input: payload, rendered } of claims) {
5938
+ const recordId = submissionInputRecordId(claim.submissionId);
5939
+ let sequence;
5940
+ const existing = joinedInputEnvelopes.get(claim.submissionId);
5941
+ if (existing !== void 0) sequence = existing.sequence;
5942
+ else {
5943
+ const envelope = yield* makeEnvelope(recordId, UserInputRecorded.make({
5944
+ submissionId: claim.submissionId,
5945
+ kind: "steering",
5946
+ runId,
5947
+ input: claim.inputPayload,
5948
+ ...payload.messageAdmission === void 0 ? {} : { messageAdmission: payload.messageAdmission }
5949
+ }));
5950
+ sequence = (yield* appendBatch(ctx, CanonicalBatch.make({
5951
+ batchId: submissionInputBatchId(claim.submissionId),
5952
+ producerId: config.producerId,
5953
+ records: [envelope]
5954
+ }))).firstSequence;
5955
+ knownIds.add(recordId);
5956
+ yield* hit("join:after-canonical-append");
5957
+ }
5958
+ yield* session.markJoined(claim.submissionId, {
5959
+ recordId,
5960
+ sequence
5961
+ });
5962
+ deliveredJoinInputs.add(claim.submissionId);
5963
+ joinedInputs.push({
5964
+ ...payload,
5965
+ rendered
5966
+ });
6027
5967
  }
6028
- if (consumed > limit) return denied("SubagentBudgetExhausted", `The parent Run exhausted its shared ${amount} budget`);
5968
+ return joinedInputs;
5969
+ }));
5970
+ return yield* Effect.forEach(joinedInputs, (joinedInput) => (joinedInput.rendered === void 0 ? renderJoinedInput(joinedInput.input, joinedInput.messageAdmission) : Effect.succeed(joinedInput.rendered)).pipe(Effect.map((input) => ({
5971
+ kind: "steering",
5972
+ input
5973
+ }))));
5974
+ })
5975
+ };
5976
+ /**
5977
+ * Durable child establishment: `establish` performs or replays
5978
+ * the idempotent get-or-create establishment protocol under the
5979
+ * parent's ownership fence and reports where the one child stands; `join` appends the
5980
+ * atomic `[SubagentJoined, ToolCallSettled]` settlement batch (SUB-019) and applies the
5981
+ * reservation release. Both use the halt side channel exactly like the durability/step
5982
+ * hooks: the engine wraps a `CoordinatorHalt` into `SubagentDurabilityError` in the
5983
+ * handler channel while the Attempt aborts with the original infrastructure failure.
5984
+ */
5985
+ const establishmentGate = yield* Semaphore.make(1);
5986
+ const establishSubagent = (request) => recordHalt(Effect.gen(function* () {
5987
+ const toolCallId = request.toolCallId;
5988
+ const turnInfo = currentToolTurn;
5989
+ if (turnInfo === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} established before any canonical response commit` });
5990
+ const denied = (errorTag, message) => ({
5991
+ _tag: "denied",
5992
+ errorTag,
5993
+ message: boundedText(message)
5994
+ });
5995
+ let requestedPayload = subagentState.requested.get(toolCallId);
5996
+ if (requestedPayload === void 0) {
5997
+ if (request.depth !== delegationDepth + 1) return denied("SubagentDepthUnsupported", `The child depth must be exactly one greater than its source depth ${delegationDepth}`);
5998
+ let targetDigests = request.targetDigests;
5999
+ if (request.target !== void 0) {
6000
+ if (request.target.id !== request.targetAgentId) return denied("SubagentBindingUnavailable", "The child target identity differs from its Definition");
6001
+ const binding = yield* resolveDefinitionBinding(registeredBindings, request.target).pipe(Effect.result);
6002
+ if (binding._tag === "Failure") return denied("SubagentBindingUnavailable", binding.failure.message);
6003
+ if (targetDigests !== void 0 && (targetDigests.agent !== binding.success.digests.agent || targetDigests.model !== binding.success.digests.model || targetDigests.tools !== binding.success.digests.tools)) return denied("SubagentDigestsInvalid", "The explicit child digests differ from its exact registration");
6004
+ targetDigests = binding.success.digests;
6029
6005
  }
6030
- }
6031
- const childInputDigest = yield* withCrypto(digestJson(childInput.value));
6032
- const grantDigest = yield* withCrypto(digestJson(grant.value));
6033
- const allocationDigest = yield* withCrypto(digestJson(allocation.value));
6034
- const reservationId = childReservationIdFor(runId, toolCallId);
6035
- const subtree = delegationDepth === 0 ? void 0 : yield* workerRuntime.reserveSubtree(submission.threadId, SubtreeBudgetReserved.make({
6036
- reservationId,
6037
- executionRunId: runId,
6038
- sourceSubmissionId: submissionId,
6039
- childThreadId: childThreadIdFor(submissionId, toolCallId),
6040
- lifetime: "attached",
6041
- depth: request.depth,
6042
- policy: request.policy,
6043
- grant: decodedGrant.value,
6044
- budget: request.budget
6045
- })).pipe(Effect.result);
6046
- if (subtree?._tag === "Failure") {
6047
- if (subtree.failure.reason === "storage") return yield* LedgerError.make({
6048
- operation: "reserve-subtree",
6049
- message: "Subtree reservation is unavailable"
6006
+ const decodedDigests = yield* decodeDefinitionDigests(targetDigests).pipe(Effect.option);
6007
+ if (Option.isNone(decodedDigests)) return denied("SubagentDigestsInvalid", "The declared child Binding digests are not valid stored digests");
6008
+ const childInput = yield* decodePersisted(request.encodedChildInput).pipe(Effect.option);
6009
+ if (Option.isNone(childInput)) return denied("SubagentInputUnpersistable", "The prepared child input does not satisfy the canonical persistence bounds");
6010
+ const grant = yield* decodePersisted(request.encodedGrant).pipe(Effect.option);
6011
+ const allocation = yield* decodePersisted(request.encodedAllocation).pipe(Effect.option);
6012
+ if (Option.isNone(grant) || Option.isNone(allocation)) return denied("SubagentDeclarationUnpersistable", "The delegation grant or allocation does not satisfy the canonical persistence bounds");
6013
+ const decodedGrant = Schema.decodeUnknownOption(SubagentGrant)(grant.value);
6014
+ if (Option.isNone(decodedGrant)) return denied("SubagentGrantInvalid", "The child authority grant is invalid");
6015
+ if (request.policy === void 0 || request.budget === void 0) return denied("SubagentBudgetInvalid", "New durable children require their full execution policy and subtree allocation");
6016
+ if (request.toolCallAllowance !== void 0 && !Schema.is(SubagentRequested.fields.toolCallAllowance)(request.toolCallAllowance)) return denied("SubagentAllowanceInvalid", "The child Tool Call allowance must be a positive integer");
6017
+ if (request.policy !== void 0 && !Schema.is(AgentPolicy)(request.policy)) return denied("SubagentPolicyInvalid", "The resolved child policy is invalid");
6018
+ if (request.budget !== void 0) {
6019
+ if (!Schema.is(SubagentBudgetReservation)(request.budget)) return denied("SubagentBudgetInvalid", "The shared delegation budget is invalid");
6020
+ const decodedAllocation = Schema.decodeUnknownOption(SubagentReservationAmounts)(allocation.value);
6021
+ if (Option.isNone(decodedAllocation) || !Equal.equals(decodedAllocation.value, request.budget.allocation)) return denied("SubagentBudgetInvalid", "The reserved allocation differs from its budget declaration");
6022
+ const { caps, allocation: requested } = request.budget;
6023
+ const prior = [...subagentState.requested.values()];
6024
+ if (prior.some((entry) => entry.budget === void 0 || !Equal.equals(entry.budget.caps, caps))) return denied("SubagentParentBudgetConflict", "Delegations in one parent Run must share the same caps");
6025
+ if (caps.maxTotalChildInvocations !== void 0 && prior.reduce((sum, entry) => sum + 1 + (entry.budget?.descendantInvocations ?? 0), 1 + (request.budget.descendantInvocations ?? 0)) > caps.maxTotalChildInvocations) return denied("SubagentBudgetExhausted", "The parent Run exhausted its child invocation budget");
6026
+ const active = prior.filter((entry) => !subagentState.joined.has(entry.toolCallId));
6027
+ if (caps.maxConcurrentChildren !== void 0 && active.length >= caps.maxConcurrentChildren) return denied("SubagentBudgetExhausted", "The parent Run exhausted its concurrent child budget");
6028
+ const dimensions = [
6029
+ ["turns", "maxTurns"],
6030
+ ["toolCalls", "maxToolCalls"],
6031
+ ["durationMillis", "maxDurationMillis"],
6032
+ ["inputTokens", "maxInputTokens"],
6033
+ ["outputTokens", "maxOutputTokens"],
6034
+ ["costMicrousd", "maxCostMicrousd"],
6035
+ ["resultBytes", "maxResultBytes"]
6036
+ ];
6037
+ const accounting = Schema.Struct({ consumed: SubagentReservationAmounts });
6038
+ for (const [amount, cap] of dimensions) {
6039
+ const limit = caps[cap];
6040
+ if (limit === void 0) continue;
6041
+ let consumed = requested[amount];
6042
+ for (const entry of prior) {
6043
+ const joined = subagentState.joined.get(entry.toolCallId);
6044
+ const observed = joined === void 0 ? Option.none() : Schema.decodeUnknownOption(accounting)(joined.finalAccounting);
6045
+ consumed += Option.isSome(observed) ? observed.value.consumed[amount] : entry.budget?.allocation[amount] ?? limit;
6046
+ }
6047
+ if (consumed > limit) return denied("SubagentBudgetExhausted", `The parent Run exhausted its shared ${amount} budget`);
6048
+ }
6049
+ }
6050
+ const childInputDigest = yield* withCrypto(digestJson(childInput.value));
6051
+ const grantDigest = yield* withCrypto(digestJson(grant.value));
6052
+ const allocationDigest = yield* withCrypto(digestJson(allocation.value));
6053
+ const reservationId = childReservationIdFor(runId, toolCallId);
6054
+ const subtree = delegationDepth === 0 ? void 0 : yield* workerRuntime.reserveSubtree(submission.threadId, SubtreeBudgetReserved.make({
6055
+ reservationId,
6056
+ executionRunId: runId,
6057
+ sourceSubmissionId: submissionId,
6058
+ childThreadId: childThreadIdFor(submissionId, toolCallId),
6059
+ lifetime: "attached",
6060
+ depth: request.depth,
6061
+ policy: request.policy,
6062
+ grant: decodedGrant.value,
6063
+ budget: request.budget
6064
+ })).pipe(Effect.result);
6065
+ if (subtree?._tag === "Failure") {
6066
+ if (subtree.failure.reason === "storage") return yield* LedgerError.make({
6067
+ operation: "reserve-subtree",
6068
+ message: "Subtree reservation is unavailable"
6069
+ });
6070
+ return denied("SubagentBudgetExhausted", `The subtree reservation was refused: ${subtree.failure.reason}`);
6071
+ }
6072
+ yield* session.reserveChildBudget({
6073
+ reservationId,
6074
+ parentToolCallId: toolCallId,
6075
+ allocation: allocation.value,
6076
+ allocationDigest
6077
+ }).pipe(Effect.catchTag("ChildReservationConflict", conflictToLedgerError("reserveChildBudget")));
6078
+ yield* hit("subagent:after-reserve");
6079
+ requestedPayload = SubagentRequested.make({
6080
+ runId,
6081
+ turnId: turnInfo.turnId,
6082
+ turn: turnInfo.turn,
6083
+ toolCallId,
6084
+ delegationId: request.delegationId,
6085
+ targetAgentId: request.targetAgentId,
6086
+ targetDigests: decodedDigests.value,
6087
+ childInput: childInput.value,
6088
+ childInputDigest,
6089
+ grantDigest,
6090
+ grant: decodedGrant.value,
6091
+ depth: request.depth,
6092
+ reservationId,
6093
+ reservationDigest: allocationDigest,
6094
+ childThreadId: childThreadIdFor(submissionId, toolCallId),
6095
+ childPrincipal: submission.principal,
6096
+ childIdempotencyKey: childIdempotencyKeyFor(runId, toolCallId),
6097
+ ...request.toolCallAllowance === void 0 ? {} : { toolCallAllowance: request.toolCallAllowance },
6098
+ ...request.policy === void 0 ? {} : { policy: request.policy },
6099
+ ...request.budget === void 0 ? {} : { budget: request.budget }
6050
6100
  });
6051
- return denied("SubagentBudgetExhausted", `The subtree reservation was refused: ${subtree.failure.reason}`);
6101
+ const requestRecordId = subagentRequestedRecordId(runId, toolCallId);
6102
+ if (!knownIds.has(requestRecordId)) {
6103
+ const envelope = yield* makeEnvelope(requestRecordId, requestedPayload);
6104
+ yield* appendBatch(ctx, CanonicalBatch.make({
6105
+ batchId: subagentRequestedBatchId(runId, toolCallId),
6106
+ producerId: config.producerId,
6107
+ records: [envelope]
6108
+ })).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
6109
+ knownIds.add(requestRecordId);
6110
+ }
6111
+ subagentState.requested.set(toolCallId, requestedPayload);
6112
+ yield* hit("subagent:after-request-append");
6052
6113
  }
6053
- yield* session.reserveChildBudget({
6054
- reservationId,
6055
- parentToolCallId: toolCallId,
6056
- allocation: allocation.value,
6057
- allocationDigest
6058
- }).pipe(Effect.catchTag("ChildReservationConflict", conflictToLedgerError("reserveChildBudget")));
6059
- yield* hit("subagent:after-reserve");
6060
- requestedPayload = SubagentRequested.make({
6061
- runId,
6062
- turnId: turnInfo.turnId,
6063
- turn: turnInfo.turn,
6064
- toolCallId,
6065
- delegationId: request.delegationId,
6066
- targetAgentId: request.targetAgentId,
6067
- targetDigests: decodedDigests.value,
6068
- childInput: childInput.value,
6069
- childInputDigest,
6070
- grantDigest,
6071
- grant: decodedGrant.value,
6072
- depth: request.depth,
6073
- reservationId,
6074
- reservationDigest: allocationDigest,
6075
- childThreadId: childThreadIdFor(submissionId, toolCallId),
6076
- childPrincipal: submission.principal,
6077
- childIdempotencyKey: childIdempotencyKeyFor(runId, toolCallId),
6078
- ...request.toolCallAllowance === void 0 ? {} : { toolCallAllowance: request.toolCallAllowance },
6079
- ...request.policy === void 0 ? {} : { policy: request.policy },
6080
- ...request.budget === void 0 ? {} : { budget: request.budget }
6114
+ const admission = yield* establishChildFromRequest(submission, requestedPayload);
6115
+ if (admission._tag === "indeterminate") return yield* LedgerError.make({
6116
+ operation: "establishSubagent",
6117
+ message: `Child admission for Tool Call ${toolCallId} is indeterminate (${admission.reason}); retrying without a second admission (SUB-031)`
6081
6118
  });
6082
- const requestRecordId = subagentRequestedRecordId(runId, toolCallId);
6083
- if (!knownIds.has(requestRecordId)) {
6084
- const envelope = yield* makeEnvelope(requestRecordId, requestedPayload);
6085
- yield* appendBatch(ctx, CanonicalBatch.make({
6086
- batchId: subagentRequestedBatchId(runId, toolCallId),
6087
- producerId: config.producerId,
6088
- records: [envelope]
6089
- })).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
6090
- knownIds.add(requestRecordId);
6091
- }
6092
- subagentState.requested.set(toolCallId, requestedPayload);
6093
- yield* hit("subagent:after-request-append");
6094
- }
6095
- const admission = yield* establishChildFromRequest(submission, requestedPayload);
6096
- if (admission._tag === "indeterminate") return yield* LedgerError.make({
6097
- operation: "establishSubagent",
6098
- message: `Child admission for Tool Call ${toolCallId} is indeterminate (${admission.reason}); retrying without a second admission (SUB-031)`
6099
- });
6100
- const childRunId = runIdForSubmission(admission.childSubmissionId);
6101
- let startedPayload = subagentState.started.get(toolCallId);
6102
- if (startedPayload === void 0) {
6103
- startedPayload = SubagentStarted.make({
6104
- runId,
6105
- toolCallId,
6106
- childThreadId: requestedPayload.childThreadId,
6107
- childSubmissionId: admission.childSubmissionId,
6108
- childReceiptId: admission.receiptId,
6109
- childRunId
6119
+ const childRunId = runIdForSubmission(admission.childSubmissionId);
6120
+ let startedPayload = subagentState.started.get(toolCallId);
6121
+ if (startedPayload === void 0) {
6122
+ startedPayload = SubagentStarted.make({
6123
+ runId,
6124
+ toolCallId,
6125
+ childThreadId: requestedPayload.childThreadId,
6126
+ childSubmissionId: admission.childSubmissionId,
6127
+ childReceiptId: admission.receiptId,
6128
+ childRunId
6129
+ });
6130
+ const startRecordId = subagentStartedRecordId(runId, toolCallId);
6131
+ if (!knownIds.has(startRecordId)) {
6132
+ const envelope = yield* makeEnvelope(startRecordId, startedPayload);
6133
+ yield* appendBatch(ctx, CanonicalBatch.make({
6134
+ batchId: subagentStartedBatchId(runId, toolCallId),
6135
+ producerId: config.producerId,
6136
+ records: [envelope]
6137
+ })).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
6138
+ knownIds.add(startRecordId);
6139
+ }
6140
+ subagentState.started.set(toolCallId, startedPayload);
6141
+ yield* hit("subagent:after-start-append");
6142
+ } else if (startedPayload.childSubmissionId !== admission.childSubmissionId) return yield* LedgerError.make({
6143
+ operation: "establishSubagent",
6144
+ message: `The canonical SubagentStarted record names child ${startedPayload.childSubmissionId} but admission resolved ${admission.childSubmissionId}; establishment fails closed (SUB-016)`
6110
6145
  });
6111
- const startRecordId = subagentStartedRecordId(runId, toolCallId);
6112
- if (!knownIds.has(startRecordId)) {
6113
- const envelope = yield* makeEnvelope(startRecordId, startedPayload);
6146
+ yield* session.attachChildToReservation({
6147
+ reservationId: decodeChildReservationIdSync(requestedPayload.reservationId),
6148
+ childSubmissionId: startedPayload.childSubmissionId
6149
+ }).pipe(Effect.catchTag("ChildReservationConflict", conflictToLedgerError("attachChildToReservation")));
6150
+ const identity = {
6151
+ childThreadId: startedPayload.childThreadId,
6152
+ childSubmissionId: startedPayload.childSubmissionId,
6153
+ childRunId: startedPayload.childRunId,
6154
+ receiptId: startedPayload.childReceiptId
6155
+ };
6156
+ const child = yield* ledger.lookup(SubmissionLookupById.make({ submissionId: startedPayload.childSubmissionId }));
6157
+ if (Option.isNone(child)) return yield* LedgerError.make({
6158
+ operation: "establishSubagent",
6159
+ message: `Established child ${startedPayload.childSubmissionId} is unknown to the ledger`
6160
+ });
6161
+ if (child.value.state !== "settled") return {
6162
+ _tag: "waiting",
6163
+ ...identity
6164
+ };
6165
+ const verification = yield* verifySettledChild(submission, requestedPayload, startedPayload.childSubmissionId);
6166
+ if (verification._tag === "mismatch") return denied("SubagentVerificationFailed", verification.message);
6167
+ return {
6168
+ _tag: "settled",
6169
+ ...identity,
6170
+ outcome: verification.value.outcome,
6171
+ encodedResult: verification.value.encodedResult,
6172
+ ...yield* verifiedChildUsage(verification.value, startedPayload.childRunId),
6173
+ ...verification.value.settlement.finishReason === void 0 ? {} : { finishReason: verification.value.settlement.finishReason }
6174
+ };
6175
+ }).pipe(establishmentGate.withPermits(1)));
6176
+ const joinSubagent = (request) => recordHalt(Effect.gen(function* () {
6177
+ const toolCallId = request.toolCallId;
6178
+ const turnInfo = currentToolTurn;
6179
+ if (turnInfo === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined before any canonical response commit` });
6180
+ const requestedPayload = subagentState.requested.get(toolCallId);
6181
+ const startedPayload = subagentState.started.get(toolCallId);
6182
+ if (requestedPayload === void 0 || startedPayload === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined without canonical establishment records` });
6183
+ const reservationId = decodeChildReservationIdSync(requestedPayload.reservationId);
6184
+ const joinedRecordId = subagentJoinedRecordId(runId, toolCallId);
6185
+ let finalAccounting;
6186
+ const existingJoined = subagentState.joined.get(toolCallId);
6187
+ if (existingJoined !== void 0) finalAccounting = existingJoined.finalAccounting;
6188
+ else {
6189
+ const encodedResult = yield* decodePersisted(request.encodedResult).pipe(Effect.mapError((cause) => RunJournalError.make({
6190
+ message: `The projected result of Tool Call ${toolCallId} exceeds canonical persistence bounds`,
6191
+ cause
6192
+ })));
6193
+ const accounting = yield* decodePersisted(request.encodedAccounting).pipe(Effect.mapError((cause) => RunJournalError.make({
6194
+ message: `The join accounting of Tool Call ${toolCallId} exceeds canonical persistence bounds`,
6195
+ cause
6196
+ })));
6197
+ const verification = yield* verifySettledChild(submission, requestedPayload, startedPayload.childSubmissionId);
6198
+ if (verification._tag === "mismatch") return yield* LedgerError.make({
6199
+ operation: "joinSubagent",
6200
+ message: `Child Settlement verification failed for Tool Call ${toolCallId}: ${verification.message}`
6201
+ });
6202
+ const verified = verification.value;
6203
+ const toolName = declaredNamesByCallId.get(toolCallId);
6204
+ if (toolName === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined without a declared Tool name` });
6205
+ yield* hit("subagent:before-join-append");
6206
+ const joinedPayload = SubagentJoined.make({
6207
+ runId,
6208
+ toolCallId,
6209
+ childSubmissionId: startedPayload.childSubmissionId,
6210
+ childSettlementId: verified.settlement.settlementId,
6211
+ childOutcome: verified.outcome,
6212
+ usageSummary: yield* childUsageSummaryOf(verified.childRecords, startedPayload.childRunId),
6213
+ ...yield* verifiedChildUsage(verified, startedPayload.childRunId),
6214
+ reservationId: requestedPayload.reservationId,
6215
+ finalAccounting: accounting
6216
+ });
6217
+ const settledRecordId = toolCallSettledRecordId(runId, turnInfo.turn, toolCallId);
6218
+ const joinedEnvelope = yield* makeEnvelope(joinedRecordId, joinedPayload);
6219
+ const settledEnvelope = yield* makeEnvelope(settledRecordId, ToolCallSettled.make({
6220
+ runId,
6221
+ toolCallId,
6222
+ toolName,
6223
+ result: encodedResult,
6224
+ isFailure: request.isFailure
6225
+ }));
6114
6226
  yield* appendBatch(ctx, CanonicalBatch.make({
6115
- batchId: subagentStartedBatchId(runId, toolCallId),
6227
+ batchId: subagentJoinBatchId(runId, toolCallId),
6116
6228
  producerId: config.producerId,
6117
- records: [envelope]
6229
+ records: [joinedEnvelope, settledEnvelope]
6118
6230
  })).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
6119
- knownIds.add(startRecordId);
6231
+ knownIds.add(joinedRecordId);
6232
+ knownIds.add(settledRecordId);
6233
+ subagentState.joined.set(toolCallId, joinedPayload);
6234
+ finalAccounting = accounting;
6235
+ yield* hit("subagent:after-join-append");
6120
6236
  }
6121
- subagentState.started.set(toolCallId, startedPayload);
6122
- yield* hit("subagent:after-start-append");
6123
- } else if (startedPayload.childSubmissionId !== admission.childSubmissionId) return yield* LedgerError.make({
6124
- operation: "establishSubagent",
6125
- message: `The canonical SubagentStarted record names child ${startedPayload.childSubmissionId} but admission resolved ${admission.childSubmissionId}; establishment fails closed (SUB-016)`
6126
- });
6127
- yield* session.attachChildToReservation({
6128
- reservationId: decodeChildReservationIdSync(requestedPayload.reservationId),
6129
- childSubmissionId: startedPayload.childSubmissionId
6130
- }).pipe(Effect.catchTag("ChildReservationConflict", conflictToLedgerError("attachChildToReservation")));
6131
- const identity = {
6132
- childThreadId: startedPayload.childThreadId,
6133
- childSubmissionId: startedPayload.childSubmissionId,
6134
- childRunId: startedPayload.childRunId,
6135
- receiptId: startedPayload.childReceiptId
6136
- };
6137
- const child = yield* ledger.lookup(SubmissionLookupById.make({ submissionId: startedPayload.childSubmissionId }));
6138
- if (Option.isNone(child)) return yield* LedgerError.make({
6139
- operation: "establishSubagent",
6140
- message: `Established child ${startedPayload.childSubmissionId} is unknown to the ledger`
6141
- });
6142
- if (child.value.state !== "settled") return {
6143
- _tag: "waiting",
6144
- ...identity
6145
- };
6146
- const verification = yield* verifySettledChild(submission, requestedPayload, startedPayload.childSubmissionId);
6147
- if (verification._tag === "mismatch") return denied("SubagentVerificationFailed", verification.message);
6148
- return {
6149
- _tag: "settled",
6150
- ...identity,
6151
- outcome: verification.value.outcome,
6152
- encodedResult: verification.value.encodedResult,
6153
- ...yield* verifiedChildUsage(verification.value, startedPayload.childRunId),
6154
- ...verification.value.settlement.finishReason === void 0 ? {} : { finishReason: verification.value.settlement.finishReason }
6155
- };
6156
- }).pipe(establishmentGate.withPermits(1)));
6157
- const joinSubagent = (request) => recordHalt(Effect.gen(function* () {
6158
- const toolCallId = request.toolCallId;
6159
- const turnInfo = currentToolTurn;
6160
- if (turnInfo === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined before any canonical response commit` });
6161
- const requestedPayload = subagentState.requested.get(toolCallId);
6162
- const startedPayload = subagentState.started.get(toolCallId);
6163
- if (requestedPayload === void 0 || startedPayload === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined without canonical establishment records` });
6164
- const reservationId = decodeChildReservationIdSync(requestedPayload.reservationId);
6165
- const joinedRecordId = subagentJoinedRecordId(runId, toolCallId);
6166
- let finalAccounting;
6167
- const existingJoined = subagentState.joined.get(toolCallId);
6168
- if (existingJoined !== void 0) finalAccounting = existingJoined.finalAccounting;
6169
- else {
6170
- const encodedResult = yield* decodePersisted(request.encodedResult).pipe(Effect.mapError((cause) => RunJournalError.make({
6171
- message: `The projected result of Tool Call ${toolCallId} exceeds canonical persistence bounds`,
6172
- cause
6173
- })));
6174
- const accounting = yield* decodePersisted(request.encodedAccounting).pipe(Effect.mapError((cause) => RunJournalError.make({
6175
- message: `The join accounting of Tool Call ${toolCallId} exceeds canonical persistence bounds`,
6176
- cause
6177
- })));
6178
- const verification = yield* verifySettledChild(submission, requestedPayload, startedPayload.childSubmissionId);
6179
- if (verification._tag === "mismatch") return yield* LedgerError.make({
6180
- operation: "joinSubagent",
6181
- message: `Child Settlement verification failed for Tool Call ${toolCallId}: ${verification.message}`
6182
- });
6183
- const verified = verification.value;
6184
- const toolName = declaredNamesByCallId.get(toolCallId);
6185
- if (toolName === void 0) return yield* RunJournalError.make({ message: `Delegation Tool Call ${toolCallId} joined without a declared Tool name` });
6186
- yield* hit("subagent:before-join-append");
6187
- const joinedPayload = SubagentJoined.make({
6237
+ yield* applyReservationRelease(reservationId, finalAccounting, {
6238
+ threadId: submission.threadId,
6188
6239
  runId,
6189
- toolCallId,
6190
- childSubmissionId: startedPayload.childSubmissionId,
6191
- childSettlementId: verified.settlement.settlementId,
6192
- childOutcome: verified.outcome,
6193
- usageSummary: yield* childUsageSummaryOf(verified.childRecords, startedPayload.childRunId),
6194
- ...yield* verifiedChildUsage(verified, startedPayload.childRunId),
6195
- reservationId: requestedPayload.reservationId,
6196
- finalAccounting: accounting
6240
+ toolCallId
6197
6241
  });
6198
- const settledRecordId = toolCallSettledRecordId(runId, turnInfo.turn, toolCallId);
6199
- const joinedEnvelope = yield* makeEnvelope(joinedRecordId, joinedPayload);
6200
- const settledEnvelope = yield* makeEnvelope(settledRecordId, ToolCallSettled.make({
6201
- runId,
6202
- toolCallId,
6203
- toolName,
6204
- result: encodedResult,
6205
- isFailure: request.isFailure
6206
- }));
6207
- yield* appendBatch(ctx, CanonicalBatch.make({
6208
- batchId: subagentJoinBatchId(runId, toolCallId),
6209
- producerId: config.producerId,
6210
- records: [joinedEnvelope, settledEnvelope]
6211
- })).pipe(Effect.catchTag("AppendConflict", () => Effect.void), Effect.asVoid);
6212
- knownIds.add(joinedRecordId);
6213
- knownIds.add(settledRecordId);
6214
- subagentState.joined.set(toolCallId, joinedPayload);
6215
- finalAccounting = accounting;
6216
- yield* hit("subagent:after-join-append");
6217
- }
6218
- yield* applyReservationRelease(reservationId, finalAccounting, {
6242
+ }));
6243
+ const subagent = {
6244
+ establish: establishSubagent,
6245
+ join: joinSubagent
6246
+ };
6247
+ const toolAuthorization = inheritedGrant === void 0 && runToolAuthorization === RunToolAuthorization.allowAllPolicy ? runToolAuthorization : { authorize: (request) => inheritedGrant !== void 0 && !inheritedGrant.allowedToolNames.includes(request.call.toolName) ? Effect.succeed({
6248
+ _tag: "denied",
6249
+ reason: "Tool exceeds the worker's immutable grant"
6250
+ }) : runToolAuthorization.authorize({
6251
+ ...request,
6252
+ input: submission.inputPayload,
6253
+ ...Schema.is(FrameworkMessage)(submission.messageAdmission) ? { frameworkMessage: submission.messageAdmission } : {}
6254
+ }) };
6255
+ const options = {
6219
6256
  threadId: submission.threadId,
6220
6257
  runId,
6221
- toolCallId
6222
- });
6223
- }));
6224
- const subagent = {
6225
- establish: establishSubagent,
6226
- join: joinSubagent
6227
- };
6228
- const toolAuthorization = inheritedGrant === void 0 && runToolAuthorization === RunToolAuthorization.allowAllPolicy ? runToolAuthorization : { authorize: (request) => inheritedGrant !== void 0 && !inheritedGrant.allowedToolNames.includes(request.call.toolName) ? Effect.succeed({
6229
- _tag: "denied",
6230
- reason: "Tool exceeds the worker's immutable grant"
6231
- }) : runToolAuthorization.authorize({
6232
- ...request,
6233
- input: submission.inputPayload,
6234
- ...Schema.is(FrameworkMessage)(submission.messageAdmission) ? { frameworkMessage: submission.messageAdmission } : {}
6235
- }) };
6236
- const options = {
6237
- threadId: submission.threadId,
6238
- runId,
6239
- history: pending === void 0 ? journal.historyBefore : resumeProjection.historyBefore,
6240
- input,
6241
- commandDrainPolicy: "all",
6242
- ...priorContext !== void 0 || journal.committedTurns > 0 || Schema.is(FrameworkMessage)(submission.messageAdmission) ? { retainedInput: submission.inputPayload } : {},
6243
- ...priorContext === void 0 ? {} : { retainedContext: Prompt.fromMessages(priorContext.prompt.content.slice(priorContext.priorHistoryLength)) },
6244
- ...Schema.is(FrameworkMessage)(submission.messageAdmission) ? { frameworkMessage: submission.messageAdmission } : {},
6245
- approval,
6246
- toolAuthorization,
6247
- ...journal.toolSelection === void 0 ? {} : { toolSelection: { toolNames: journal.toolSelection.toolNames.filter((name) => Object.hasOwn(agent.definition.toolkit.tools, name)) } },
6248
- durability,
6249
- subagent,
6250
- delegationDepth,
6251
- ...inheritedGrant === void 0 ? {} : { subagentGrant: inheritedGrant },
6252
- ...inheritedBudget === void 0 ? {} : { subagentBudget: inheritedBudget },
6253
- ...submission.workerAdmission?.origin.budgetScope === void 0 ? {} : { subagentBudgetScope: submission.workerAdmission.origin.budgetScope },
6254
- runStartedAt: runTiming.startedAt,
6255
- durationDeadline: runTiming.deadline,
6256
- ...submission.workerAdmission === void 0 ? {} : { toolCallAllowance: submission.workerAdmission.origin.toolCallAllowance },
6257
- ...submission.parentLinkage !== void 0 && childLineage?._tag === "SubagentLineageRecorded" ? { toolCallAllowance: childLineage.toolCallAllowance } : {},
6258
- ...pending === void 0 ? {} : { resume: {
6259
- ...settledCompletion === void 0 ? {} : { settledCompletion },
6260
- turn: pending.turn,
6261
- toolResultMaxBytes: pending.toolResultMaxBytes,
6262
- turnId: pending.turnId,
6263
- calls: pending.calls,
6264
- toolParameterRejections: pending.toolParameterRejections,
6265
- settled: pending.settled,
6266
- toolExposure: pending.toolExposure ?? Snapshot.make({ exposedToolNames: [...new Set(pending.calls.map((call) => call.name))] }),
6267
- ...resumeLeadingMessages === void 0 ? {} : { leadingMessages: resumeLeadingMessages },
6268
- ...resumeResponseMessages === void 0 ? {} : { responseMessages: resumeResponseMessages }
6269
- } },
6270
- ...preparedContext === void 0 ? {} : { context: preparedContext },
6271
- beforeTurn: () => Effect.gen(function* () {
6272
- if (yieldAfter !== void 0 && (yield* Clock.currentTimeMillis) >= DateTime.toEpochMillis(yieldAfter)) {
6273
- yield* Deferred.succeed(yieldSignal, void 0);
6274
- return yield* Effect.never;
6275
- }
6276
- if (submissionScheduling.yieldTo !== void 0 && (yield* Ref.get(turnCounter)) > 0) {
6277
- const candidate = yield* recordHalt(eligibleThreadHead(submission.threadId, submission.queueSequence));
6278
- if (Option.isSome(candidate) && (candidate.value.state === "ready" || candidate.value.state === "input-applied")) {
6279
- const next = yield* recordHalt(ledger.lookup(SubmissionLookupById.make({ submissionId: candidate.value.submissionId })));
6280
- if (Option.isSome(next) && next.value.agentId === submission.agentId && (next.value.state === "ready" || next.value.state === "input-applied") && (yield* recordHalt(submissionScheduling.yieldTo({
6281
- active: submission,
6282
- next: next.value
6283
- })))) {
6284
- yield* Deferred.succeed(yieldSignal, next.value.submissionId);
6285
- return yield* Effect.never;
6258
+ history: pending === void 0 ? journal.historyBefore : resumeProjection.historyBefore,
6259
+ input,
6260
+ commandDrainPolicy: "all",
6261
+ ...priorContext !== void 0 || journal.committedTurns > 0 || Schema.is(FrameworkMessage)(submission.messageAdmission) ? { retainedInput: submission.inputPayload } : {},
6262
+ ...priorContext === void 0 ? {} : { retainedContext: Prompt.fromMessages(priorContext.prompt.content.slice(priorContext.priorHistoryLength)) },
6263
+ ...Schema.is(FrameworkMessage)(submission.messageAdmission) ? { frameworkMessage: submission.messageAdmission } : {},
6264
+ approval,
6265
+ toolAuthorization,
6266
+ ...journal.toolSelection === void 0 ? {} : { toolSelection: { toolNames: journal.toolSelection.toolNames.filter((name) => Object.hasOwn(agent.definition.toolkit.tools, name)) } },
6267
+ durability,
6268
+ subagent,
6269
+ delegationDepth,
6270
+ ...inheritedGrant === void 0 ? {} : { subagentGrant: inheritedGrant },
6271
+ ...inheritedBudget === void 0 ? {} : { subagentBudget: inheritedBudget },
6272
+ ...submission.workerAdmission?.origin.budgetScope === void 0 ? {} : { subagentBudgetScope: submission.workerAdmission.origin.budgetScope },
6273
+ runStartedAt: runTiming.startedAt,
6274
+ durationDeadline: runTiming.deadline,
6275
+ ...submission.workerAdmission === void 0 ? {} : { toolCallAllowance: submission.workerAdmission.origin.toolCallAllowance },
6276
+ ...submission.parentLinkage !== void 0 && childLineage?._tag === "SubagentLineageRecorded" ? { toolCallAllowance: childLineage.toolCallAllowance } : {},
6277
+ ...pending === void 0 ? {} : { resume: {
6278
+ ...settledCompletion === void 0 ? {} : { settledCompletion },
6279
+ turn: pending.turn,
6280
+ toolResultMaxBytes: pending.toolResultMaxBytes,
6281
+ turnId: pending.turnId,
6282
+ calls: pending.calls,
6283
+ toolParameterRejections: pending.toolParameterRejections,
6284
+ settled: pending.settled,
6285
+ toolExposure: pending.toolExposure ?? Snapshot.make({ exposedToolNames: [...new Set(pending.calls.map((call) => call.name))] }),
6286
+ ...resumeLeadingMessages === void 0 ? {} : { leadingMessages: resumeLeadingMessages },
6287
+ ...resumeResponseMessages === void 0 ? {} : { responseMessages: resumeResponseMessages }
6288
+ } },
6289
+ ...preparedContext === void 0 ? {} : { context: preparedContext },
6290
+ beforeTurn: Effect.fnUntraced(function* () {
6291
+ if (yieldAfter !== void 0 && (yield* Clock.currentTimeMillis) >= DateTime.toEpochMillis(yieldAfter)) {
6292
+ yield* Deferred.succeed(yieldSignal, void 0);
6293
+ return yield* Effect.never;
6294
+ }
6295
+ if (submissionScheduling.yieldTo !== void 0 && (yield* Ref.get(turnCounter)) > 0) {
6296
+ const candidate = yield* recordHalt(eligibleThreadHead(submission.threadId, submission.queueSequence));
6297
+ if (Option.isSome(candidate) && (candidate.value.state === "ready" || candidate.value.state === "input-applied")) {
6298
+ const next = yield* recordHalt(ledger.lookup(SubmissionLookupById.make({ submissionId: candidate.value.submissionId })));
6299
+ if (Option.isSome(next) && next.value.agentId === submission.agentId && (next.value.state === "ready" || next.value.state === "input-applied") && (yield* recordHalt(submissionScheduling.yieldTo({
6300
+ active: submission,
6301
+ next: next.value
6302
+ })))) {
6303
+ yield* Deferred.succeed(yieldSignal, next.value.submissionId);
6304
+ return yield* Effect.never;
6305
+ }
6286
6306
  }
6287
6307
  }
6288
- }
6289
- }),
6290
- ...runContextPreparation.transientContext === void 0 ? {} : { transientContext: runContextPreparation.transientContext },
6291
- ...config.estimateCostMicrousd === void 0 ? {} : { estimateCostMicrousd: config.estimateCostMicrousd },
6292
- resumeUsage: {
6293
- ...journal.usage,
6294
- ...journal.policyUsage,
6295
- ...journal.usage.modelCalls === 0 && (journal.usage.unobservedModelCalls ?? 0) === 0 && !records.some(({ record }) => record.payload._tag === "ModelResponseInterrupted" && record.payload.runId === runId) ? emptyRunTotals() : runTotalsFromSummary(yield* currentUsageSummary()),
6296
- children: childUsageReportsOf(subagentState)
6297
- },
6298
- ...journal.contextWindowId === void 0 ? {} : { initialContextWindowId: journal.contextWindowId },
6299
- ...journal.protectedContext === void 0 ? {} : { protectedContext: journal.protectedContext },
6300
- ...pendingContextToolCallId === void 0 ? {} : { pendingContextToolCallId }
6301
- };
6302
- if (pending === void 0 && lineage.inputWasRecorded) {
6303
- yield* appendInterruptedAudit(ctx, runId, knownIds);
6304
- interruptedUsage = true;
6305
- }
6306
- const consume = executeWithUsageAccountingUnknown(agent, submission.inputPayload, options).pipe(Effect.provideService(AgentUpdateAcceptance, { accept: (update) => flushDeferredResponse.pipe(Effect.catch((failure) => Ref.set(haltRef, failure).pipe(Effect.andThen(Effect.fail(UpdateError.make({ reason: "storage" }))))), Effect.andThen(() => updateRuntime.emit({
6307
- updateId: update.updateId,
6308
- value: update.value,
6309
- submission,
6310
- runId,
6311
- definitions: submission.agentDigests
6312
- }).pipe(Effect.provideService(CurrentRunWriter, ctx))), Effect.catchTag(["LedgerError", "DurableRuntimeFailpointError"], (failure) => Ref.set(haltRef, failure).pipe(Effect.andThen(Effect.fail(UpdateError.make({ reason: "storage" })))))) }), Effect.provideService(ModelUsageAccounting, { noteIncompleteUsage: (turn) => Effect.sync(() => {
6313
- stagedUnobservedCalls.set(turn, (stagedUnobservedCalls.get(turn) ?? 0) + 1);
6314
- }) }), Effect.provide(ThreadHistory.layer), Effect.provideService(SubagentHost.forTool, (source) => source.threadId !== submission.threadId || source.agentId !== submission.agentId || source.runId !== runId ? SubagentHost.unavailable : workerRuntime.facet({
6315
- source,
6316
- policy: agent.definition.policy,
6317
- depth: delegationDepth,
6318
- ...inheritedGrant === void 0 ? {} : { grant: inheritedGrant }
6319
- }, submission.principal, submission.submissionId)), Effect.provideService(MessagingHost.forTool, (source) => source.threadId !== submission.threadId || source.agentId !== submission.agentId || source.runId !== runId ? MessagingHost.unavailable : messagingRuntime.forTool(source, submission.principal)), Effect.provideService(CurrentToolFailureObserver, toolFailureObserver), Effect.provideService(RunToolVisibility, runToolVisibility), Effect.provideService(RunToolScheduling, runToolScheduling), Effect.provideService(ContextCompactor, compactor), Effect.provideService(RunContextPreparation, runContextPreparation), Effect.andThen(checkpoint), Effect.catchCause((cause) => Ref.get(haltRef).pipe(Effect.flatMap((failure) => failure === void 0 ? Effect.failCause(cause) : Effect.failCause(Cause.map(cause, (error) => error instanceof CoordinatorHalt ? error : new CoordinatorHalt(failure)))))), Effect.tapCause((cause) => Option.isSome(agentApprovalPendingOption(cause)) && cause.reasons.every(Cause.isFailReason) ? Effect.flatMap(DurableApprovalSuspension, (retain) => retain === void 0 ? Effect.void : halt(retain)) : Effect.void), Effect.as({ _tag: "run" }));
6320
- const abortWatcher = halt(Effect.gen(function* () {
6321
- while (true) {
6322
- yield* Effect.sleep(config.abortPollInterval);
6323
- const intent = yield* ledger.readAbortIntent(AbortIntentRequest.make({ submissionId }));
6324
- if (intent === void 0) continue;
6325
- yield* appendAbortRecord(ctx, intent);
6326
- return { _tag: "aborted" };
6327
- }
6328
- }));
6329
- const execution = Effect.raceFirst(consume, abortWatcher);
6330
- const result = yield* (yieldAfter === void 0 && submissionScheduling.yieldTo === void 0 ? execution : Effect.raceFirst(execution, Deferred.await(yieldSignal).pipe(Effect.map((nextSubmissionId) => ({
6331
- _tag: "yielded",
6332
- ...nextSubmissionId === void 0 ? {} : { nextSubmissionId }
6333
- }))))).pipe(Effect.provideService(IdGenerator$1, idGenerator)).pipe(Effect.catchCauseFilter(Cause.findError, (error, cause) => {
6334
- if (isCoordinatorHaltCause(cause)) return Effect.failCause(Cause.map(cause, (halt) => halt.failure));
6335
- if (cause.reasons.some((reason) => reason._tag === "Fail" && reason.error instanceof AgentInputDecodeError)) return Effect.failCause(Cause.map(cause, () => BindingUnavailable.make({
6336
- agentId: agent.definition.id,
6337
- message: "The current Binding cannot decode accepted input"
6338
- })));
6339
- const approvalPending = agentApprovalPendingOption(cause);
6340
- if (Option.isSome(approvalPending)) {
6341
- const residual = Cause.fromReasons(cause.reasons.filter((reason) => reason._tag !== "Fail"));
6342
- if (residual.reasons.length > 0) return Effect.failCause(residual);
6343
- return decodeToolCallIdUnknown(approvalPending.value.toolCallId).pipe(Effect.orDie, Effect.map((toolCallId) => ({
6344
- _tag: "suspendedRun",
6345
- toolCallId
6346
- })));
6308
+ }),
6309
+ ...runContextPreparation.transientContext === void 0 ? {} : { transientContext: runContextPreparation.transientContext },
6310
+ ...config.estimateCostMicrousd === void 0 ? {} : { estimateCostMicrousd: config.estimateCostMicrousd },
6311
+ resumeUsage: {
6312
+ ...journal.usage,
6313
+ ...journal.policyUsage,
6314
+ ...journal.usage.modelCalls === 0 && (journal.usage.unobservedModelCalls ?? 0) === 0 && !records.some(({ record }) => record.payload._tag === "ModelResponseInterrupted" && record.payload.runId === runId) ? emptyRunTotals() : runTotalsFromSummary(yield* currentUsageSummary()),
6315
+ children: childUsageReportsOf(subagentState)
6316
+ },
6317
+ ...journal.contextWindowId === void 0 ? {} : { initialContextWindowId: journal.contextWindowId },
6318
+ ...journal.protectedContext === void 0 ? {} : { protectedContext: journal.protectedContext },
6319
+ ...pendingContextToolCallId === void 0 ? {} : { pendingContextToolCallId }
6320
+ };
6321
+ if (pending === void 0 && lineage.inputWasRecorded) {
6322
+ yield* appendInterruptedAudit(ctx, runId, knownIds);
6323
+ interruptedUsage = true;
6347
6324
  }
6348
- const childPending = agentChildPendingOption(error);
6349
- if (Option.isSome(childPending)) return Effect.succeed({
6350
- _tag: "suspendedChildRun",
6351
- children: childPending.value.children
6352
- });
6353
- return Effect.gen(function* () {
6354
- const halted = yield* Ref.get(haltRef);
6355
- if (halted !== void 0) return yield* halted;
6356
- yield* flushDeferredResponse;
6357
- if (error instanceof AgentToolAuthorizationDenied) {
6325
+ const consume = executeWithUsageAccountingUnknown(agent, submission.inputPayload, options).pipe(Effect.provideService(AgentUpdateAcceptance, { accept: (update) => flushDeferredResponse.pipe(Effect.catch((failure) => Ref.set(haltRef, failure).pipe(Effect.andThen(Effect.fail(UpdateError.make({ reason: "storage" }))))), Effect.andThen(() => updateRuntime.emit({
6326
+ updateId: update.updateId,
6327
+ value: update.value,
6328
+ submission,
6329
+ runId,
6330
+ definitions: submission.agentDigests
6331
+ }).pipe(Effect.provideService(CurrentRunWriter, ctx))), Effect.catchTag(["LedgerError", "DurableRuntimeFailpointError"], (failure) => Ref.set(haltRef, failure).pipe(Effect.andThen(Effect.fail(UpdateError.make({ reason: "storage" })))))) }), Effect.provideService(ModelUsageAccounting, { noteIncompleteUsage: (turn) => Effect.sync(() => {
6332
+ stagedUnobservedCalls.set(turn, (stagedUnobservedCalls.get(turn) ?? 0) + 1);
6333
+ }) }), (body) => body.pipe(Effect.provideServiceEffect(ThreadHistory, ThreadHistory.makeFromStore), Effect.provideServiceEffect(Store, makeMemoryStore), Effect.scoped), Effect.provideContext(runServices.pipe(Context.add(SubagentHost.forTool, (source) => source.threadId !== submission.threadId || source.agentId !== submission.agentId || source.runId !== runId ? SubagentHost.unavailable : workerRuntime.facet({
6334
+ source,
6335
+ policy: agent.definition.policy,
6336
+ depth: delegationDepth,
6337
+ ...inheritedGrant === void 0 ? {} : { grant: inheritedGrant }
6338
+ }, submission.principal, submission.submissionId)), Context.add(MessagingHost.forTool, (source) => source.threadId !== submission.threadId || source.agentId !== submission.agentId || source.runId !== runId ? MessagingHost.unavailable : messagingRuntime.forTool(source, submission.principal)))), Effect.andThen(checkpoint), Effect.catchCause((cause) => Ref.get(haltRef).pipe(Effect.flatMap((failure) => failure === void 0 ? Effect.failCause(cause) : Effect.failCause(Cause.map(cause, (error) => error instanceof CoordinatorHalt ? error : new CoordinatorHalt(failure)))))), Effect.tapCause((cause) => Option.isSome(agentApprovalPendingOption(cause)) && cause.reasons.every(Cause.isFailReason) ? Effect.flatMap(DurableApprovalSuspension, (retain) => retain === void 0 ? Effect.void : halt(retain)) : Effect.void), Effect.as({ _tag: "run" }));
6339
+ const abortWatcher = halt(Effect.gen(function* () {
6340
+ while (true) {
6341
+ yield* Effect.sleep(config.abortPollInterval);
6358
6342
  const intent = yield* ledger.readAbortIntent(AbortIntentRequest.make({ submissionId }));
6359
- if (intent !== void 0) {
6360
- yield* appendAbortRecord(ctx, intent);
6361
- return { _tag: "aborted" };
6362
- }
6343
+ if (intent === void 0) continue;
6344
+ yield* appendAbortRecord(ctx, intent);
6345
+ return { _tag: "aborted" };
6363
6346
  }
6364
- if (cause.reasons.some((reason) => reason._tag === "Die" || reason._tag === "Fail" && !(reason.error instanceof AgentApprovalDenied) && !(reason.error instanceof AgentToolAuthorizationDenied))) yield* Effect.logError("Agent run failed", cause).pipe(Effect.annotateLogs({
6347
+ }));
6348
+ const result = yield* Effect.raceAllFirst([
6349
+ consume,
6350
+ abortWatcher,
6351
+ ...yieldAfter === void 0 && submissionScheduling.yieldTo === void 0 ? [] : [Deferred.await(yieldSignal).pipe(Effect.map((nextSubmissionId) => ({
6352
+ _tag: "yielded",
6353
+ ...nextSubmissionId === void 0 ? {} : { nextSubmissionId }
6354
+ })))]
6355
+ ]).pipe(Effect.provideService(IdGenerator$1, idGenerator)).pipe(Effect.catchCauseFilter(Cause.findError, (error, cause) => {
6356
+ if (isCoordinatorHaltCause(cause)) return Effect.failCause(Cause.map(cause, (halt) => halt.failure));
6357
+ if (cause.reasons.some((reason) => reason._tag === "Fail" && reason.error instanceof AgentInputDecodeError)) return Effect.failCause(Cause.map(cause, () => BindingUnavailable.make({
6365
6358
  agentId: agent.definition.id,
6366
- runId,
6367
- threadId: ctx.threadId,
6368
- submissionId,
6369
- attemptId: lineage.attemptId
6370
- }));
6371
- return {
6372
- _tag: "failedRun",
6373
- outcome: yield* failureOutcome(error, cause, {
6359
+ message: "The current Binding cannot decode accepted input"
6360
+ })));
6361
+ const approvalPending = agentApprovalPendingOption(cause);
6362
+ if (Option.isSome(approvalPending)) {
6363
+ const residual = Cause.fromReasons(cause.reasons.filter((reason) => reason._tag !== "Fail"));
6364
+ if (residual.reasons.length > 0) return Effect.failCause(residual);
6365
+ return decodeToolCallIdUnknown(approvalPending.value.toolCallId).pipe(Effect.orDie, Effect.map((toolCallId) => ({
6366
+ _tag: "suspendedRun",
6367
+ toolCallId
6368
+ })));
6369
+ }
6370
+ const childPending = agentChildPendingOption(error);
6371
+ if (Option.isSome(childPending)) return Effect.succeed({
6372
+ _tag: "suspendedChildRun",
6373
+ children: childPending.value.children
6374
+ });
6375
+ return Effect.gen(function* () {
6376
+ const halted = yield* Ref.get(haltRef);
6377
+ if (halted !== void 0) return yield* halted;
6378
+ yield* flushDeferredResponse;
6379
+ if (error instanceof AgentToolAuthorizationDenied) {
6380
+ const intent = yield* ledger.readAbortIntent(AbortIntentRequest.make({ submissionId }));
6381
+ if (intent !== void 0) {
6382
+ yield* appendAbortRecord(ctx, intent);
6383
+ return { _tag: "aborted" };
6384
+ }
6385
+ }
6386
+ if (cause.reasons.some((reason) => reason._tag === "Die" || reason._tag === "Fail" && !(reason.error instanceof AgentApprovalDenied) && !(reason.error instanceof AgentToolAuthorizationDenied))) yield* Effect.logError("Agent run failed", cause).pipe(Effect.annotateLogs({
6374
6387
  agentId: agent.definition.id,
6375
6388
  runId,
6376
6389
  threadId: ctx.threadId,
6377
6390
  submissionId,
6378
6391
  attemptId: lineage.attemptId
6379
- })
6392
+ }));
6393
+ return {
6394
+ _tag: "failedRun",
6395
+ outcome: yield* failureOutcome(error, cause, {
6396
+ agentId: agent.definition.id,
6397
+ runId,
6398
+ threadId: ctx.threadId,
6399
+ submissionId,
6400
+ attemptId: lineage.attemptId
6401
+ })
6402
+ };
6403
+ });
6404
+ }));
6405
+ if (result._tag === "yielded") return result;
6406
+ if (result._tag === "suspendedRun") return approvalSuspension(result.toolCallId);
6407
+ if (result._tag === "suspendedChildRun") return childSuspension(result.children);
6408
+ if (result._tag === "aborted") {
6409
+ yield* flushDeferredResponse;
6410
+ return {
6411
+ ...abortedRunPhase(yield* currentUsageSummary()),
6412
+ uncommittedModelUsage: uncommittedModelUsage()
6380
6413
  };
6414
+ }
6415
+ if (result._tag === "failedRun") return {
6416
+ ...result.outcome,
6417
+ usageSummary: yield* currentUsageSummary(),
6418
+ uncommittedModelUsage: uncommittedModelUsage()
6419
+ };
6420
+ const committedCompletion = completionState.committed;
6421
+ if (committedCompletion === void 0) return yield* LedgerError.make({
6422
+ operation: "runModel",
6423
+ message: "Agent Run ended without a committed completion"
6381
6424
  });
6382
- }));
6383
- if (result._tag === "yielded") return result;
6384
- if (result._tag === "suspendedRun") return approvalSuspension(result.toolCallId);
6385
- if (result._tag === "suspendedChildRun") return childSuspension(result.children);
6386
- if (result._tag === "aborted") {
6387
- yield* flushDeferredResponse;
6388
6425
  return {
6389
- ...abortedRunPhase(yield* currentUsageSummary()),
6426
+ _tag: "completed",
6427
+ result: committedCompletion.output,
6428
+ ...committedCompletion.runDisposition === void 0 ? {} : { runDisposition: committedCompletion.runDisposition },
6429
+ ...committedCompletion.finishReason === void 0 ? {} : { finishReason: committedCompletion.finishReason },
6430
+ ...committedCompletion.exhausted === void 0 ? {} : { exhausted: committedCompletion.exhausted },
6431
+ usageSummary: yield* currentUsageSummary(),
6390
6432
  uncommittedModelUsage: uncommittedModelUsage()
6391
6433
  };
6392
6434
  }
6393
- if (result._tag === "failedRun") return {
6394
- ...result.outcome,
6395
- usageSummary: yield* currentUsageSummary(),
6396
- uncommittedModelUsage: uncommittedModelUsage()
6397
- };
6398
- const committedCompletion = completionState.committed;
6399
- if (committedCompletion === void 0) return yield* LedgerError.make({
6400
- operation: "runModel",
6401
- message: "Agent Run ended without a committed completion"
6402
- });
6403
- return {
6404
- _tag: "completed",
6405
- result: committedCompletion.output,
6406
- ...committedCompletion.runDisposition === void 0 ? {} : { runDisposition: committedCompletion.runDisposition },
6407
- ...committedCompletion.finishReason === void 0 ? {} : { finishReason: committedCompletion.finishReason },
6408
- ...committedCompletion.exhausted === void 0 ? {} : { exhausted: committedCompletion.exhausted },
6409
- usageSummary: yield* currentUsageSummary(),
6410
- uncommittedModelUsage: uncommittedModelUsage()
6411
- };
6412
- });
6435
+ );
6413
6436
  /**
6414
6437
  * One ownership period over the claimed lane head. The step order mirrors the pure recovery
6415
6438
  * classifier's decision table, so a fresh Attempt and a recovering Attempt take the same path
@@ -6417,16 +6440,16 @@ const make = Effect.fnUntraced(function* (bindings) {
6417
6440
  * (Unknown Outcomes, or a durable approval suspension) — no settlement occurs and the
6418
6441
  * obligation stays owed.
6419
6442
  */
6420
- const runAttempt = (registeredAgent, session, resumeAfterRetention, onHandoff, yieldAfter) => Effect.gen(function* () {
6443
+ const runAttempt = Effect.fnUntraced(function* (registeredAgent, session, resumeAfterRetention, onHandoff, yieldAfter, freshlyAdmitted = false) {
6421
6444
  yield* session.checkActive;
6422
- const checkpointPrompt = yield* promptHistory.take({ threadId: session.threadId }).pipe(Effect.provideService(ThreadStore, store), Effect.provideService(ThreadReader, reader), Effect.provideService(Crypto.Crypto, crypto));
6445
+ const checkpointPrompt = yield* promptHistory.take({ threadId: session.threadId }).pipe(Effect.provideService(ThreadStore, store), Effect.provideContext(journalServices));
6423
6446
  let committedPromptSuffix;
6424
6447
  const storageSession = session;
6425
6448
  yield* Effect.addFinalizer(() => Effect.sync(() => {
6426
6449
  committedPromptSuffix?.discard();
6427
6450
  committedPromptSuffix = void 0;
6428
6451
  }));
6429
- session = yield* withProgressSession({
6452
+ const promptSession = {
6430
6453
  ...storageSession,
6431
6454
  append: (batch, executions) => {
6432
6455
  const suffix = committedPromptSuffix;
@@ -6445,12 +6468,45 @@ const make = Effect.fnUntraced(function* (bindings) {
6445
6468
  replayed: result.replayed
6446
6469
  }))), Effect.tapCause(() => Effect.sync(() => suffix.discard())));
6447
6470
  }
6448
- });
6471
+ };
6472
+ session = yield* withProgressSession(promptSession);
6449
6473
  const { claim, threadId } = session;
6450
6474
  const submissionId = claim.submissionId;
6451
- const snapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId }));
6475
+ let prepared = freshlyAdmitted && session.withInitialization !== void 0 ? yield* session.withInitialization(Effect.gen(function* () {
6476
+ const snapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId }));
6477
+ const submission = snapshot.submission;
6478
+ if (submission.state !== "ready" || submission.workerAdmission !== void 0 || submission.messageAdmission !== void 0 || submission.parentLinkage !== void 0 || snapshot.inputApplied !== void 0 || snapshot.abortIntent !== void 0 || snapshot.approvalDecisions.length !== 0) return void 0;
6479
+ yield* ensureThreadCreated$1(threadId, submission.agentId, submission.agentDigests);
6480
+ yield* session.refresh;
6481
+ const before = (yield* session.tail).sequence;
6482
+ const view = yield* recoveryView(threadId, before, [submissionId], runIdForSubmission(submissionId));
6483
+ if (view.progress !== void 0 || view.context !== void 0 || view.operational.length !== 0 || view.records.some(({ record }) => record.payload._tag !== "ThreadCreated")) return void 0;
6484
+ const progress = progressWriters.get(session);
6485
+ const applyInput = applyCanonicalInput(session, submission, session, view.records, void 0);
6486
+ yield* progress === void 0 ? applyInput : progress.withVerifiedEmptyRun(runIdForSubmission(submissionId), before, applyInput).pipe(Effect.provideService(CurrentRunWriter, promptSession));
6487
+ const through = (yield* session.tail).sequence;
6488
+ const added = yield* selectedRange(threadId, [submissionId], through, before);
6489
+ const records = [...view.records, ...added];
6490
+ const accepted = progressWriters.get(session)?.acceptedCheckpoint(runIdForSubmission(submissionId));
6491
+ if (accepted === void 0 || accepted.throughSequence !== through || accepted.progress.runId !== runIdForSubmission(submissionId) || accepted.progress.submissionId !== submissionId) return void 0;
6492
+ const start = yield* makeRunStart(submission, Duration.toMillis(registeredAgent.definition.policy.maxDuration), records, view.operational).pipe(Effect.provideService(CurrentRunWriter, session));
6493
+ return {
6494
+ snapshot,
6495
+ through,
6496
+ view: {
6497
+ ...view,
6498
+ records,
6499
+ progress: accepted.progress,
6500
+ progressThrough: accepted.throughSequence,
6501
+ operational: accepted.operational
6502
+ },
6503
+ start
6504
+ };
6505
+ })) : void 0;
6506
+ const preparedInput = prepared !== void 0;
6507
+ const snapshot = prepared?.snapshot ?? (yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId })));
6452
6508
  const submission = snapshot.submission;
6453
- yield* ensureThreadCreated$1(threadId, submission.agentId, submission.agentDigests);
6509
+ if (prepared === void 0) yield* ensureThreadCreated$1(threadId, submission.agentId, submission.agentDigests);
6454
6510
  if (submission.workerAdmission?.origin.reporting?.mode === "standard") yield* updateRuntime.repairRun(threadId, submissionId);
6455
6511
  if (submission.workerAdmission !== void 0) yield* workerRuntime.ensureOrigin(submission.workerAdmission.origin).pipe(Effect.mapError((cause) => LedgerError.make({
6456
6512
  operation: "worker-origin",
@@ -6458,10 +6514,11 @@ const make = Effect.fnUntraced(function* (bindings) {
6458
6514
  cause
6459
6515
  })));
6460
6516
  if (submission.state === "admitted") yield* ledger.markReady(MarkReadyRequest.make({ submissionId }));
6461
- yield* session.refresh;
6517
+ if (prepared === void 0) yield* session.refresh;
6462
6518
  const ctx = session;
6463
- let controlThrough = (yield* session.tail).sequence;
6464
- const initialView = yield* recoveryView(threadId, controlThrough, [submissionId], runIdForSubmission(submissionId));
6519
+ let controlThrough = prepared?.through ?? (yield* session.tail).sequence;
6520
+ const initialThrough = controlThrough;
6521
+ const initialView = prepared?.view ?? (yield* recoveryView(threadId, initialThrough, [submissionId], runIdForSubmission(submissionId)));
6465
6522
  let journalMetadata;
6466
6523
  const retainControl = controlRecords([submissionId]);
6467
6524
  const collectControl = (record) => {
@@ -6473,7 +6530,7 @@ const make = Effect.fnUntraced(function* (bindings) {
6473
6530
  journalMetadata = void 0;
6474
6531
  return metadata;
6475
6532
  };
6476
- let records = yield* Stream.runCollect(initialView.canonical.pipe(Stream.filter(collectControl)));
6533
+ let records = initialView.records.filter(collectControl);
6477
6534
  const refreshControl = Effect.fnUntraced(function* (throughSequence) {
6478
6535
  const through = throughSequence ?? (yield* store.inspectTail(ThreadTailRequest.make({ threadId }))).tailSequence;
6479
6536
  if (through > controlThrough) {
@@ -6512,8 +6569,8 @@ const make = Effect.fnUntraced(function* (bindings) {
6512
6569
  }
6513
6570
  return Option.some(yield* settleAborted(ctx, submission, session.publishSettlement, snapshot.abortIntent, evidence, knownIds));
6514
6571
  }
6515
- yield* applyCanonicalInput(ctx, submission, session, records, snapshot.inputApplied);
6516
- const start = yield* makeRunStart(submission, Duration.toMillis(agent.definition.policy.maxDuration), yield* refreshControl()).pipe(Effect.provideService(CurrentRunWriter, ctx));
6572
+ if (prepared === void 0) yield* applyCanonicalInput(ctx, submission, session, records, snapshot.inputApplied);
6573
+ const start = prepared?.start ?? (yield* makeRunStart(submission, Duration.toMillis(agent.definition.policy.maxDuration), yield* refreshControl(), initialView.operational).pipe(Effect.provideService(CurrentRunWriter, ctx)));
6517
6574
  const savedRunTiming = start.timing;
6518
6575
  const commitStart = Effect.flatMap(CurrentRunStart, (publication) => publication.commit()).pipe(Effect.provideService(CurrentRunStart, start.publication));
6519
6576
  const runTiming = workerOrigin === void 0 ? savedRunTiming : {
@@ -6521,13 +6578,17 @@ const make = Effect.fnUntraced(function* (bindings) {
6521
6578
  deadline: DateTime.makeUnsafe(Math.min(DateTime.toEpochMillis(savedRunTiming.deadline), workerOrigin.expiresAtMillis))
6522
6579
  };
6523
6580
  let expiredChildObligation = false;
6581
+ let preparedControl = prepared !== void 0;
6524
6582
  if ((yield* Clock.currentTimeMillis) >= DateTime.toEpochMillis(runTiming.deadline)) {
6583
+ prepared = void 0;
6584
+ preparedControl = false;
6525
6585
  yield* commitStart;
6526
6586
  yield* reconcileRetainedChildren(ctx, submission, session);
6527
6587
  expiredChildObligation = yield* completeJoinedReleases(submission);
6528
6588
  }
6529
6589
  const ordinaryCallsResolved = Effect.gen(function* () {
6530
- const reconciliationRecords = yield* refreshControl();
6590
+ const reconciliationRecords = preparedControl ? records : yield* refreshControl();
6591
+ preparedControl = false;
6531
6592
  const reconciliationEvidence = yield* evidenceFor(reconciliationRecords, submissionId, true, snapshot.hostSubmissionId);
6532
6593
  if (reconciliationEvidence.openToolCalls.length === 0) return true;
6533
6594
  const reconciliationSnapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId }));
@@ -6544,7 +6605,7 @@ const make = Effect.fnUntraced(function* (bindings) {
6544
6605
  return true;
6545
6606
  });
6546
6607
  if (!expiredChildObligation && !(yield* ordinaryCallsResolved)) return Option.none();
6547
- const continuationRecords = yield* refreshControl();
6608
+ const continuationRecords = prepared === void 0 ? yield* refreshControl() : records;
6548
6609
  const continuation = yield* pendingToolBatchFor(continuationRecords, runIdForSubmission(submissionId));
6549
6610
  if (continuation !== void 0) {
6550
6611
  const current = {
@@ -6615,15 +6676,17 @@ const make = Effect.fnUntraced(function* (bindings) {
6615
6676
  }
6616
6677
  const lineage = {
6617
6678
  attemptId: claim.attemptId,
6618
- inputWasRecorded: evidence.inputRecorded
6679
+ inputWasRecorded: !preparedInput && evidence.inputRecorded
6619
6680
  };
6620
6681
  let approvalDecisionIntents = snapshot.approvalDecisions;
6621
6682
  while (true) {
6622
- yield* session.refresh;
6683
+ const initialization = prepared;
6684
+ prepared = void 0;
6685
+ if (initialization === void 0) yield* session.refresh;
6623
6686
  const tail = yield* session.tail;
6624
- const currentRecords = yield* refreshControl(tail.sequence);
6625
- const view = yield* recoveryView(threadId, tail.sequence, [submissionId], runIdForSubmission(submissionId), currentRecords);
6626
- let canonical = view.canonical;
6687
+ const currentRecords = initialization === void 0 ? yield* refreshControl(tail.sequence) : records;
6688
+ const view = initialization?.view ?? (yield* recoveryView(threadId, tail.sequence, [submissionId], runIdForSubmission(submissionId), currentRecords));
6689
+ let canonical = Stream.fromIterable(view.records);
6627
6690
  let initialJournal;
6628
6691
  if (view.context === void 0) {
6629
6692
  const original = currentRecords.find(({ record }) => record.payload._tag === "UserInputRecorded" && record.payload.kind === "user" && record.payload.submissionId === submissionId);
@@ -6733,7 +6796,7 @@ const make = Effect.fnUntraced(function* (bindings) {
6733
6796
  if (outcome._tag === "completed" && initialJournal?.cacheable && initialJournal.history !== void 0) yield* promptHistory.complete({ threadId: session.threadId }, initialJournal.original, initialJournal.history, committedPromptSuffix).pipe(Effect.provideService(CurrentRunWriter, session), Effect.provideService(ThreadStore, store), Effect.provideService(ThreadReader, reader));
6734
6797
  return Option.some(settlement);
6735
6798
  }
6736
- }).pipe(Effect.scoped);
6799
+ }, (effect) => effect.pipe(Effect.scoped));
6737
6800
  const acquireAdministrativeClaim = (threadId, handoff) => runStorage.claim(ClaimRequest.make({
6738
6801
  threadId,
6739
6802
  ...handoff === void 0 ? {} : { handoff }
@@ -6751,6 +6814,8 @@ const make = Effect.fnUntraced(function* (bindings) {
6751
6814
  if (Option.isNone(claimed)) return Option.none();
6752
6815
  const session = claimed.value;
6753
6816
  const { claim } = session;
6817
+ const freshlyAdmitted = unclaimedAdmissions.get(claim.submissionId) === threadId;
6818
+ unclaimedAdmissions.delete(claim.submissionId);
6754
6819
  firstClaimedSubmissionId ??= claim.submissionId;
6755
6820
  const attributes = {
6756
6821
  threadId,
@@ -6789,7 +6854,7 @@ const make = Effect.fnUntraced(function* (bindings) {
6789
6854
  deferredSubmissionIds: [...handoff?.deferredSubmissionIds ?? [], claim.submissionId],
6790
6855
  submissionId: nextSubmissionId
6791
6856
  });
6792
- }, options?.yieldAfter), threadId, claim);
6857
+ }, options?.yieldAfter, freshlyAdmitted), threadId, claim);
6793
6858
  }));
6794
6859
  while (true) {
6795
6860
  resumeAfterRetention = false;
@@ -6819,7 +6884,7 @@ const make = Effect.fnUntraced(function* (bindings) {
6819
6884
  settlements.push(settlement.value);
6820
6885
  }
6821
6886
  }).pipe((body) => withProcessing(threadId, body));
6822
- const processThreadImpl = (agent, threadId) => Effect.gen(function* () {
6887
+ const processThreadImpl = Effect.fnUntraced(function* (agent, threadId) {
6823
6888
  const binding = yield* makeLegacyWorkerBinding(agent);
6824
6889
  return yield* drainThread((submission) => submission.agentId === binding.agentId ? Effect.succeed(binding) : Effect.fail(BindingUnavailable.make({
6825
6890
  agentId: submission.agentId,
@@ -7221,8 +7286,7 @@ const make = Effect.fnUntraced(function* (bindings) {
7221
7286
  const snapshot = yield* ledger.loadRecoverySnapshot(RecoverySnapshotRequest.make({ submissionId: submission.submissionId }));
7222
7287
  if (snapshot.hostSubmissionId !== void 0 && !history.submissionIds.includes(snapshot.hostSubmissionId)) {
7223
7288
  const hostId = snapshot.hostSubmissionId;
7224
- const hostView = yield* recoveryView(submission.threadId, history.throughSequence, [hostId]);
7225
- const hostRecords = yield* Stream.runCollect(hostView.canonical.pipe(Stream.filter(controlRecords([hostId]))));
7289
+ const hostRecords = (yield* recoveryView(submission.threadId, history.throughSequence, [hostId])).records.filter(controlRecords([hostId]));
7226
7290
  const merged = new Map(history.records.map((entry) => [entry.sequence, entry]));
7227
7291
  for (const entry of hostRecords) merged.set(entry.sequence, entry);
7228
7292
  history = {
@@ -7383,7 +7447,7 @@ const make = Effect.fnUntraced(function* (bindings) {
7383
7447
  cause
7384
7448
  })));
7385
7449
  });
7386
- const recoverOwnedWork = Effect.fnUntraced(function* (request, recoveredAdmissions = /* @__PURE__ */ new Map()) {
7450
+ const recoverOwnedWork = Effect.fnUntraced(function* (request, recoveredAdmissions = /* @__PURE__ */ new Map(), deferUnclaimedAdmissions = false) {
7387
7451
  const { threadId, work: entry } = yield* Schema.decodeEffect(WorkRecoveryRequest)(request).pipe(Effect.mapError((cause) => ThreadStoreError.make({
7388
7452
  operation: "recover work",
7389
7453
  message: "Invalid selected work",
@@ -7410,7 +7474,10 @@ const make = Effect.fnUntraced(function* (bindings) {
7410
7474
  });
7411
7475
  if (owner._tag === "Admission") {
7412
7476
  if (entry.id !== workId("admission", owner.submissionId) || entry.stateReference._tag !== "Submission" || entry.stateReference.submissionId !== owner.submissionId) return yield* invalid();
7413
- if ((yield* lookupKnownSubmission("recover work", owner.submissionId)).threadId !== threadId) return yield* invalid();
7477
+ const original = yield* lookupKnownSubmission("recover work", owner.submissionId);
7478
+ if (original.threadId !== threadId) return yield* invalid();
7479
+ if (deferUnclaimedAdmissions && unclaimedAdmissions.get(owner.submissionId) === threadId && original.state === "ready" && !storageOwner.hasOwner(threadId) && (yield* ledger.readAbortIntent(AbortIntentRequest.make({ submissionId: owner.submissionId }))) === void 0) return report("deferred");
7480
+ unclaimedAdmissions.delete(owner.submissionId);
7414
7481
  const submission = yield* recoverAdmission(owner.submissionId);
7415
7482
  return report(submission.disposition, submission);
7416
7483
  }
@@ -7616,6 +7683,16 @@ const make = Effect.fnUntraced(function* (bindings) {
7616
7683
  let complete = false;
7617
7684
  let phase = "history";
7618
7685
  const outcome = yield* isolateRecovery(Effect.gen(function* () {
7686
+ if (workCursor === void 0 && options?.deferUnclaimedAdmissions === true && workDiscovery.isOnlyFreshAdmission !== void 0 && !storageOwner.hasOwner(threadId)) {
7687
+ const fresh = [...unclaimedAdmissions].find(([, owner]) => owner === threadId);
7688
+ if (fresh !== void 0 && (yield* workDiscovery.isOnlyFreshAdmission({
7689
+ threadId,
7690
+ submissionId: fresh[0]
7691
+ }))) {
7692
+ complete = true;
7693
+ return;
7694
+ }
7695
+ }
7619
7696
  for (let pages = 0; pages < 8 && workReports.length < 32; pages++) {
7620
7697
  phase = "history";
7621
7698
  const workPage = yield* discoverWork({
@@ -7628,7 +7705,7 @@ const make = Effect.fnUntraced(function* (bindings) {
7628
7705
  const repaired = yield* recoverOwnedWork({
7629
7706
  threadId,
7630
7707
  work
7631
- }, recoveredAdmissions);
7708
+ }, recoveredAdmissions, options?.deferUnclaimedAdmissions === true);
7632
7709
  workReports.push(repaired);
7633
7710
  if (repaired.submission !== void 0 && !reportedAdmissions.has(repaired.submission.submissionId)) {
7634
7711
  reportedAdmissions.add(repaired.submission.submissionId);
@@ -7735,7 +7812,7 @@ const make = Effect.fnUntraced(function* (bindings) {
7735
7812
  queueSequence: admitted.queueSequence
7736
7813
  });
7737
7814
  }
7738
- const admitted = yield* ledger.admit(request);
7815
+ const admitted = yield* ledger.admit(request, { readyIfInitialized: true });
7739
7816
  yield* hit("submit:after-admit");
7740
7817
  const receipt = Receipt.make({
7741
7818
  receiptId: admitted.receiptId,
@@ -7744,10 +7821,19 @@ const make = Effect.fnUntraced(function* (bindings) {
7744
7821
  queueSequence: admitted.queueSequence
7745
7822
  });
7746
7823
  if (admitted.replayed && admitted.state !== "admitted") return receipt;
7747
- yield* materializeThread(options.threadId);
7748
- yield* ensureThreadCreated$1(options.threadId, agent.definition.id, options.definitions);
7749
- yield* hit("submit:after-materialize");
7750
- yield* ledger.markReady(MarkReadyRequest.make({ submissionId: admitted.submissionId }));
7824
+ if (admitted.state === "admitted") {
7825
+ yield* materializeThread(options.threadId);
7826
+ yield* ensureThreadCreated$1(options.threadId, agent.definition.id, options.definitions);
7827
+ yield* hit("submit:after-materialize");
7828
+ yield* ledger.markReady(MarkReadyRequest.make({ submissionId: admitted.submissionId }));
7829
+ }
7830
+ if (!admitted.replayed && messageAdmission === void 0 && options.workerAdmission === void 0) {
7831
+ unclaimedAdmissions.set(admitted.submissionId, options.threadId);
7832
+ if (unclaimedAdmissions.size > 128) {
7833
+ const oldest = unclaimedAdmissions.keys().next().value;
7834
+ if (oldest !== void 0) unclaimedAdmissions.delete(oldest);
7835
+ }
7836
+ }
7751
7837
  yield* wake.notify(options.threadId);
7752
7838
  return receipt;
7753
7839
  });
@@ -7776,10 +7862,6 @@ const make = Effect.fnUntraced(function* (bindings) {
7776
7862
  submissionId: receipt.submissionId
7777
7863
  });
7778
7864
  if (snapshot.value.state !== "settled") return Option.none();
7779
- const settlement = yield* ledger.finalizeSettlement(SettlementFinalization.make({
7780
- submissionId: receipt.submissionId,
7781
- settlementId: submissionSettlementId(receipt.submissionId)
7782
- }));
7783
7865
  const canonical = yield* getRecord({
7784
7866
  threadId: receipt.threadId,
7785
7867
  recordId: submissionSettlementRecordId(receipt.submissionId)
@@ -7793,6 +7875,23 @@ const make = Effect.fnUntraced(function* (bindings) {
7793
7875
  message: "Finalized Submission has no canonical Settlement"
7794
7876
  });
7795
7877
  const record = yield* settlementPayloadFromRecord(canonical.value.record, receipt.submissionId);
7878
+ const finalized = snapshot.value;
7879
+ const retainedFinalization = finalized.settledAt !== void 0 && finalized.settledRecordId !== void 0 && finalized.settledOutcome !== void 0;
7880
+ if (retainedFinalization && (finalized.settledRecordId !== canonical.value.record.recordId || finalized.settledOutcome !== record.outcome || canonical.value.batchId !== submissionSettlementBatchId(receipt.submissionId))) return yield* LedgerError.make({
7881
+ operation: "awaitSettlement",
7882
+ message: "Settled projection disagrees with its canonical Settlement"
7883
+ });
7884
+ const settlement = retainedFinalization ? Settlement.make({
7885
+ submissionId: receipt.submissionId,
7886
+ settlementId: record.settlementId,
7887
+ receiptId: record.receiptId,
7888
+ outcome: record.outcome,
7889
+ ...record.outcome === "failed" ? { failure: record.result } : {},
7890
+ settledAt: finalized.settledAt
7891
+ }) : yield* ledger.finalizeSettlement(SettlementFinalization.make({
7892
+ submissionId: receipt.submissionId,
7893
+ settlementId: submissionSettlementId(receipt.submissionId)
7894
+ }));
7796
7895
  if (record.receiptId !== receipt.receiptId || record.settlementId !== settlement.settlementId || record.outcome !== settlement.outcome) return yield* LedgerError.make({
7797
7896
  operation: "awaitSettlement",
7798
7897
  message: "Canonical Settlement disagrees with the receipt or finalized outcome"
@@ -8348,4 +8447,4 @@ var DurableAgentRuntime = class DurableAgentRuntime extends Context.Service()("@
8348
8447
  //#endregion
8349
8448
  export { DurableApprovalSuspension as a, RecoveryFailure as c, WorkRecoveryReport as d, WorkRecoveryRequest as f, recoveryRepairRecordId as g, recoveryRepairBatchId as h, DurableApprovalResolver as i, RecoveryReport as l, isolateRecovery as m, DurableAgentRuntime as n, DurableRuntimeConfig as o, childReservationIdFor as p, DurableAgentRuntime_exports as r, RecoveryBlocked as s, ApprovalSuspensionError as t, RecoverySweepResult as u };
8350
8449
 
8351
- //# sourceMappingURL=DurableAgentRuntime-BAmSkWYr.mjs.map
8450
+ //# sourceMappingURL=DurableAgentRuntime-CPlw5_7e.mjs.map