@yielded/agent 0.1.0-beta.176 → 0.1.0-beta.178

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 (198) hide show
  1. package/dist/{Admin-DTDihBra.d.mts → Admin-NvXFPDIM.d.mts} +32 -12
  2. package/dist/{Agent-BiRbr73L.mjs → Agent-B3J0B4l6.mjs} +6 -3
  3. package/dist/Agent-B3J0B4l6.mjs.map +1 -0
  4. package/dist/{AgentRuntime-DaDKMasp.mjs → AgentRuntime-DrQfy4cL.mjs} +7 -6
  5. package/dist/AgentRuntime-DrQfy4cL.mjs.map +1 -0
  6. package/dist/{AgentRuntime-CHDyRbSf.d.mts → AgentRuntime-Dx5u_FJD.d.mts} +6 -6
  7. package/dist/{Digest-C3EODOee.mjs → Digest-ft4ku9pj.mjs} +2 -2
  8. package/dist/{Digest-C3EODOee.mjs.map → Digest-ft4ku9pj.mjs.map} +1 -1
  9. package/dist/{DurableAgentRuntime-BJbuIqQq.mjs → DurableAgentRuntime-CWhu1exp.mjs} +142 -96
  10. package/dist/DurableAgentRuntime-CWhu1exp.mjs.map +1 -0
  11. package/dist/{DurableStep-DXGn7KQ4.d.mts → DurableStep-CAJnlgfL.d.mts} +5 -4
  12. package/dist/{EventSource-Cc58uEso.d.mts → EventSource-DNyaWmyQ.d.mts} +2 -2
  13. package/dist/{MessageDelivery-ClHg7c0O.d.mts → MessageDelivery-CLzWJImC.d.mts} +4 -4
  14. package/dist/{Messaging-SVu6rWV8.d.mts → Messaging-DpEZMTVE.d.mts} +2 -2
  15. package/dist/{MessagingHost-CZCyrnvJ.mjs → MessagingHost-BILcuj0V.mjs} +2 -2
  16. package/dist/{MessagingHost-CZCyrnvJ.mjs.map → MessagingHost-BILcuj0V.mjs.map} +1 -1
  17. package/dist/{MessagingHost-C6SOAcoG.d.mts → MessagingHost-BKxDskYj.d.mts} +2 -2
  18. package/dist/{PreparedInputAdmission-CjcX1OP0.d.mts → PreparedInputAdmission-BQ9UCLFS.d.mts} +3 -3
  19. package/dist/{Records-DzL4Kbtw.mjs → Records-CZRedCE7.mjs} +3 -3
  20. package/dist/{Records-DzL4Kbtw.mjs.map → Records-CZRedCE7.mjs.map} +1 -1
  21. package/dist/{RunContinuation-CWHuciup.mjs → RunContinuation-BF95Ncv2.mjs} +12 -14
  22. package/dist/RunContinuation-BF95Ncv2.mjs.map +1 -0
  23. package/dist/{RunContinuation-DSnUTSSb.d.mts → RunContinuation-CL0wBsQE.d.mts} +3 -6
  24. package/dist/{RunJournal-DGblbFas.mjs → RunJournal-oJLo-pjS.mjs} +3 -3
  25. package/dist/{RunJournal-DGblbFas.mjs.map → RunJournal-oJLo-pjS.mjs.map} +1 -1
  26. package/dist/{RunOptions-Be77lKVZ.d.mts → RunOptions-BANtohGk.d.mts} +3 -3
  27. package/dist/{RunStorage-BF2YgWkg.mjs → RunStorage-DlfvMfHM.mjs} +20 -6
  28. package/dist/RunStorage-DlfvMfHM.mjs.map +1 -0
  29. package/dist/{Scheduling-07_dsGED.mjs → Scheduling-BebkRVc2.mjs} +3 -3
  30. package/dist/{Scheduling-07_dsGED.mjs.map → Scheduling-BebkRVc2.mjs.map} +1 -1
  31. package/dist/{Subagent-xhN_aD1r.d.mts → Subagent-5ulnV6An.d.mts} +9 -9
  32. package/dist/{Subagent-CexndZSp.mjs → Subagent-C7F7c8Op.mjs} +3 -3
  33. package/dist/{Subagent-CexndZSp.mjs.map → Subagent-C7F7c8Op.mjs.map} +1 -1
  34. package/dist/{SubagentHost-D1xBgn9g.d.mts → SubagentHost-CikdGpmk.d.mts} +2 -2
  35. package/dist/{Subscription-DuC_PcGx.d.mts → Subscription-D2yn6Eo3.d.mts} +2 -2
  36. package/dist/{SubscriptionInput-B1IeAEDi.d.mts → SubscriptionInput-Cog4x7Rd.d.mts} +2 -2
  37. package/dist/{ThreadImport-ZgWxf7bB.mjs → ThreadImport-BoTfjjrz.mjs} +9 -9
  38. package/dist/{ThreadImport-ZgWxf7bB.mjs.map → ThreadImport-BoTfjjrz.mjs.map} +1 -1
  39. package/dist/{ThreadImport-D_Biid6w.d.mts → ThreadImport-CMKa8U7y.d.mts} +42 -42
  40. package/dist/{ThreadStore-BC4V-mY-.mjs → ThreadStore-D2rqtt7k.mjs} +17 -12
  41. package/dist/ThreadStore-D2rqtt7k.mjs.map +1 -0
  42. package/dist/{ThreadTransfer-S7FnTRHt.mjs → ThreadTransfer-BFolkpEp.mjs} +4 -4
  43. package/dist/{ThreadTransfer-S7FnTRHt.mjs.map → ThreadTransfer-BFolkpEp.mjs.map} +1 -1
  44. package/dist/{Worker-CHRaIsWu.d.mts → Worker-CLYgfqhF.d.mts} +7 -5
  45. package/dist/{Worker-DZjdMjZn.mjs → Worker-CtuUwYOK.mjs} +4 -2
  46. package/dist/Worker-CtuUwYOK.mjs.map +1 -0
  47. package/dist/{WorkerAdmission-C47Vy_cK.mjs → WorkerAdmission-CtX1HRkm.mjs} +6 -6
  48. package/dist/{WorkerAdmission-C47Vy_cK.mjs.map → WorkerAdmission-CtX1HRkm.mjs.map} +1 -1
  49. package/dist/{agent-registration-a6QYaG3h.mjs → agent-registration-Dt57NAP6.mjs} +5 -5
  50. package/dist/{agent-registration-a6QYaG3h.mjs.map → agent-registration-Dt57NAP6.mjs.map} +1 -1
  51. package/dist/capabilities/BrowserUse.d.mts +6 -2
  52. package/dist/capabilities/BrowserUse.mjs +23 -5
  53. package/dist/capabilities/BrowserUse.mjs.map +1 -1
  54. package/dist/capabilities/CodeMode.mjs +2 -1
  55. package/dist/capabilities/CodeMode.mjs.map +1 -1
  56. package/dist/capabilities/Commands.d.mts +1 -1
  57. package/dist/capabilities/ContextTools.mjs +1 -1
  58. package/dist/capabilities/McpClient.mjs +1 -1
  59. package/dist/capabilities/MemoryNotes.d.mts +1 -1
  60. package/dist/capabilities/MemoryNotes.mjs +2 -1
  61. package/dist/capabilities/MemoryNotes.mjs.map +1 -1
  62. package/dist/capabilities/Messaging.d.mts +1 -1
  63. package/dist/capabilities/Messaging.mjs +2 -2
  64. package/dist/capabilities/RunHooks.d.mts +1 -1
  65. package/dist/capabilities/Subagent.d.mts +2 -2
  66. package/dist/capabilities/Subagent.mjs +2 -2
  67. package/dist/capabilities/ToolDiscovery.mjs +1 -1
  68. package/dist/capabilities/WebCapture.mjs +1 -1
  69. package/dist/capabilities/WebSearch.mjs +1 -1
  70. package/dist/core/Agent.mjs +1 -1
  71. package/dist/core/Worker.d.mts +1 -1
  72. package/dist/core/Worker.mjs +1 -1
  73. package/dist/durable/ActivityStore.mjs +1 -1
  74. package/dist/durable/Admin.d.mts +1 -1
  75. package/dist/durable/Admin.mjs +1 -1
  76. package/dist/durable/AgentRegistration.d.mts +1 -1
  77. package/dist/durable/AgentRegistration.mjs +1 -1
  78. package/dist/durable/Certification.d.mts +1 -1
  79. package/dist/durable/CommittedActivity.d.mts +1 -1
  80. package/dist/durable/CommittedActivity.mjs +3 -3
  81. package/dist/durable/Digest.mjs +1 -1
  82. package/dist/durable/DurableAgentRuntime.d.mts +1 -1
  83. package/dist/durable/DurableAgentRuntime.mjs +2 -2
  84. package/dist/durable/EventSource.d.mts +1 -1
  85. package/dist/durable/EventSource.mjs +1 -1
  86. package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
  87. package/dist/durable/LifecyclePublication.d.mts +1 -1
  88. package/dist/durable/LifecyclePublication.mjs +3 -3
  89. package/dist/durable/MessageDelivery.d.mts +1 -1
  90. package/dist/durable/MessageDelivery.mjs +3 -3
  91. package/dist/durable/MessageDeliveryStoreConformance.d.mts +40 -40
  92. package/dist/durable/MessageDeliveryStoreConformance.mjs +3 -3
  93. package/dist/durable/PersistentHistory.d.mts +1 -1
  94. package/dist/durable/PersistentHistory.mjs +4 -4
  95. package/dist/durable/PreparedInputAdmission.d.mts +1 -1
  96. package/dist/durable/RecordFormat.mjs +1 -1
  97. package/dist/durable/Records.mjs +1 -1
  98. package/dist/durable/Recovery.d.mts +1 -1
  99. package/dist/durable/Recovery.mjs +1 -1
  100. package/dist/durable/RunContinuation.d.mts +2 -2
  101. package/dist/durable/RunContinuation.mjs +3 -3
  102. package/dist/durable/RunJournal.d.mts +1 -1
  103. package/dist/durable/RunJournal.mjs +1 -1
  104. package/dist/durable/RunStorage.d.mts +1 -1
  105. package/dist/durable/RunStorage.mjs +1 -1
  106. package/dist/durable/Schedule.mjs +1 -1
  107. package/dist/durable/ScheduleStoreConformance.mjs +1 -1
  108. package/dist/durable/ScheduleTransition.mjs +1 -1
  109. package/dist/durable/Scheduling.d.mts +1 -1
  110. package/dist/durable/Scheduling.mjs +1 -1
  111. package/dist/durable/SettlementPublisher.d.mts +1 -1
  112. package/dist/durable/SettlementPublisher.mjs +3 -3
  113. package/dist/durable/SubmissionLedger.d.mts +1 -1
  114. package/dist/durable/SubmissionLedger.mjs +4 -4
  115. package/dist/durable/SubmissionLedgerConformance.d.mts +1 -1
  116. package/dist/durable/SubmissionLedgerConformance.mjs +7 -7
  117. package/dist/durable/SubmissionStatus.d.mts +1 -1
  118. package/dist/durable/Subscription.d.mts +1 -1
  119. package/dist/durable/Subscription.mjs +2 -2
  120. package/dist/durable/SubscriptionInput.d.mts +1 -1
  121. package/dist/durable/SubscriptionInput.mjs +2 -2
  122. package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
  123. package/dist/durable/SubscriptionStoreConformance.mjs +1 -1
  124. package/dist/durable/SubscriptionTools.d.mts +3 -3
  125. package/dist/durable/SubscriptionTools.mjs +2 -1
  126. package/dist/durable/SubscriptionTools.mjs.map +1 -1
  127. package/dist/durable/SubscriptionTransition.d.mts +1 -1
  128. package/dist/durable/SubscriptionTransition.mjs +1 -1
  129. package/dist/durable/Subscriptions.d.mts +5 -5
  130. package/dist/durable/Subscriptions.mjs +2 -2
  131. package/dist/durable/ThreadArchiveRange.d.mts +1 -1
  132. package/dist/durable/ThreadArchiveRange.mjs +1 -1
  133. package/dist/durable/ThreadContextHistory.d.mts +1 -1
  134. package/dist/durable/ThreadContextHistory.mjs +2 -2
  135. package/dist/durable/ThreadContextHistoryProjection.mjs +1 -1
  136. package/dist/durable/ThreadImport.d.mts +1 -1
  137. package/dist/durable/ThreadImport.mjs +1 -1
  138. package/dist/durable/ThreadInvariants.d.mts +3 -3
  139. package/dist/durable/ThreadInvariants.mjs +4 -4
  140. package/dist/durable/ThreadProjection.mjs +1 -1
  141. package/dist/durable/ThreadProjectionMaintenance.d.mts +1 -1
  142. package/dist/durable/ThreadReader.d.mts +1 -1
  143. package/dist/durable/ThreadReader.mjs +1 -1
  144. package/dist/durable/ThreadStore.d.mts +2 -2
  145. package/dist/durable/ThreadStore.mjs +3 -3
  146. package/dist/durable/ThreadStoreConformance.d.mts +2 -1
  147. package/dist/durable/ThreadStoreConformance.mjs +4 -4
  148. package/dist/durable/ThreadTransfer.d.mts +1 -1
  149. package/dist/durable/ThreadTransfer.mjs +1 -1
  150. package/dist/durable/ThreadWork.d.mts +1 -1
  151. package/dist/durable/ThreadWork.mjs +5 -5
  152. package/dist/durable/ToolReconciler.mjs +1 -1
  153. package/dist/durable/WorkerAdmission.d.mts +1 -1
  154. package/dist/durable/WorkerAdmission.mjs +1 -1
  155. package/dist/durable/WorkerHost.d.mts +2 -2
  156. package/dist/durable/WorkerHost.mjs +1 -1
  157. package/dist/engine/AgentRuntime.d.mts +1 -1
  158. package/dist/engine/AgentRuntime.mjs +1 -1
  159. package/dist/engine/DurableStep.d.mts +2 -2
  160. package/dist/engine/DurableStep.mjs +1 -11
  161. package/dist/engine/DurableStep.mjs.map +1 -1
  162. package/dist/engine/MessagingHost.d.mts +1 -1
  163. package/dist/engine/MessagingHost.mjs +1 -1
  164. package/dist/engine/RunOptions.d.mts +1 -1
  165. package/dist/engine/SubagentHost.d.mts +1 -1
  166. package/dist/engine/SubagentHost.mjs +1 -1
  167. package/dist/index.d.mts +16 -16
  168. package/dist/index.mjs +15 -15
  169. package/dist/{run-context-reader-DvTEq2RC.d.mts → run-context-reader-kpO9xhP2.d.mts} +2 -2
  170. package/dist/sandbox/CodeExecutor.d.mts +3 -1
  171. package/dist/sandbox/CodeExecutor.mjs +3 -1
  172. package/dist/sandbox/CodeExecutor.mjs.map +1 -1
  173. package/dist/tool-execution-Ba7tO7Pt.mjs +17 -0
  174. package/dist/tool-execution-Ba7tO7Pt.mjs.map +1 -0
  175. package/package.json +1 -1
  176. package/src/capabilities/BrowserUse.ts +25 -5
  177. package/src/capabilities/CodeMode.ts +1 -0
  178. package/src/core/Worker.ts +3 -1
  179. package/src/core/internal/agent-updates.ts +9 -1
  180. package/src/core/internal/tool-execution.ts +33 -0
  181. package/src/durable/DurableAgentRuntime.ts +152 -151
  182. package/src/durable/RunContinuation.ts +44 -32
  183. package/src/durable/RunStorage.ts +56 -15
  184. package/src/durable/ThreadStore.ts +11 -0
  185. package/src/durable/internal/agent-updates.ts +59 -3
  186. package/src/durable/internal/prompt-history-cache.ts +19 -3
  187. package/src/durable/internal/record-encoding.ts +8 -7
  188. package/src/durable/internal/worker-host.ts +3 -1
  189. package/src/engine/DurableStep.ts +5 -31
  190. package/src/engine/internal/agent-runtime.ts +2 -1
  191. package/src/sandbox/CodeExecutor.ts +3 -1
  192. package/dist/Agent-BiRbr73L.mjs.map +0 -1
  193. package/dist/AgentRuntime-DaDKMasp.mjs.map +0 -1
  194. package/dist/DurableAgentRuntime-BJbuIqQq.mjs.map +0 -1
  195. package/dist/RunContinuation-CWHuciup.mjs.map +0 -1
  196. package/dist/RunStorage-BF2YgWkg.mjs.map +0 -1
  197. package/dist/ThreadStore-BC4V-mY-.mjs.map +0 -1
  198. package/dist/Worker-DZjdMjZn.mjs.map +0 -1
@@ -156,7 +156,7 @@ import {
156
156
  resolveWorkerBinding,
157
157
  CurrentBindingSelection,
158
158
  } from "./internal/agent-registration.ts";
159
- import { makeAgentUpdateRuntime } from "./internal/agent-updates.ts";
159
+ import { makeAgentUpdateRuntime, nativeUpdateAccepted } from "./internal/agent-updates.ts";
160
160
  import { inspectForeignDiagnostic, safeUnknownString } from "./internal/foreign-diagnostic.ts";
161
161
  import { initialContext, type InitialContextInput } from "./internal/initial-context.ts";
162
162
  import {
@@ -174,6 +174,7 @@ import {
174
174
  type CommittedPromptSuffix,
175
175
  type PromptHistory,
176
176
  } from "./internal/prompt-history-cache.ts";
177
+ import { captureRecord } from "./internal/record-encoding.ts";
177
178
  import { RunContextReader } from "./internal/run-context-reader.ts";
178
179
  import { readRunContext } from "./internal/run-context.ts";
179
180
  import * as ThreadInitialization from "./internal/thread-initialization.ts";
@@ -403,7 +404,6 @@ import {
403
404
  getRunInput,
404
405
  ThreadReader,
405
406
  MAX_THREAD_EXPORT_PAGE_BYTES,
406
- PreparedAppend,
407
407
  type CommitBatch,
408
408
  type ExecutionUpdate,
409
409
  } from "./ThreadStore.ts";
@@ -3094,6 +3094,22 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
3094
3094
  recovered += 1;
3095
3095
  });
3096
3096
 
3097
+ // Retry permission cannot mask a recorded outcome or require a runnable old binding.
3098
+ // Explicit factual resolutions and abort instructions retain their own handling below.
3099
+ if (
3100
+ (intent === undefined || intent.resolution._tag === "SafeToRetry") &&
3101
+ declared !== undefined &&
3102
+ nativeUpdateAccepted(submission, declared, records)
3103
+ ) {
3104
+ yield* appendClosedCall(ctx, submissionId, knownIds, call, {
3105
+ result: { value: { emitted: true }, isFailure: false },
3106
+ resolution: "completed-with-result",
3107
+ author: RECONCILER_AUTHOR,
3108
+ reason: "The exact native update was canonically accepted",
3109
+ });
3110
+ recovered += 1;
3111
+ continue;
3112
+ }
3097
3113
  if (intent !== undefined) {
3098
3114
  switch (intent.resolution._tag) {
3099
3115
  case "AbortSubmission":
@@ -4902,6 +4918,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
4902
4918
  progressThrough: CanonicalSequence | undefined,
4903
4919
  continuation: RunContinuation | undefined,
4904
4920
  priorContext: RunJournalContext | undefined,
4921
+ operational: ReadonlyArray<RecordEnvelope>,
4905
4922
  journalMetadata: JournalMetadata | undefined,
4906
4923
  lineage: AttemptLineage,
4907
4924
  approvalDecisions: ReadonlyArray<ApprovalDecisionIntent>,
@@ -5437,13 +5454,9 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
5437
5454
  );
5438
5455
  });
5439
5456
 
5440
- const activeExecution = yield* reader.readExecution({ threadId: ctx.threadId, runId });
5441
-
5442
- const recordedCompletion = Option.isSome(activeExecution)
5443
- ? activeExecution.value.operational.find(
5444
- (record) => record.recordId === runCompletedRecordId(runId),
5445
- )?.payload
5446
- : undefined;
5457
+ const recordedCompletion = operational.find(
5458
+ (record) => record.recordId === runCompletedRecordId(runId),
5459
+ )?.payload;
5447
5460
 
5448
5461
  if (recordedCompletion !== undefined) {
5449
5462
  if (recordedCompletion._tag !== "RunCompleted" || recordedCompletion.runId !== runId) {
@@ -7814,19 +7827,26 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
7814
7827
  ...(config.estimateCostMicrousd === undefined
7815
7828
  ? {}
7816
7829
  : { estimateCostMicrousd: config.estimateCostMicrousd }),
7817
- resumeUsage: {
7818
- ...journal.usage,
7819
- ...journal.policyUsage,
7820
- ...(journal.usage.modelCalls === 0 &&
7821
- (journal.usage.unobservedModelCalls ?? 0) === 0 &&
7822
- !records.some(
7823
- ({ record }) =>
7824
- record.payload._tag === "ModelResponseInterrupted" && record.payload.runId === runId,
7825
- )
7826
- ? emptyRunTotals()
7827
- : runTotalsFromSummary(yield* currentUsageSummary())),
7828
- children: childUsageReportsOf(subagentState),
7829
- },
7830
+ // An exact committed history prefix followed only by this input creates the
7831
+ // initial journal above. There is no resumed accounting to reconstruct or decode.
7832
+ ...(freshPrefix !== undefined && continuation === undefined
7833
+ ? {}
7834
+ : {
7835
+ resumeUsage: {
7836
+ ...journal.usage,
7837
+ ...journal.policyUsage,
7838
+ ...(journal.usage.modelCalls === 0 &&
7839
+ (journal.usage.unobservedModelCalls ?? 0) === 0 &&
7840
+ !records.some(
7841
+ ({ record }) =>
7842
+ record.payload._tag === "ModelResponseInterrupted" &&
7843
+ record.payload.runId === runId,
7844
+ )
7845
+ ? emptyRunTotals()
7846
+ : runTotalsFromSummary(yield* currentUsageSummary())),
7847
+ children: childUsageReportsOf(subagentState),
7848
+ },
7849
+ }),
7830
7850
  ...(journal.contextWindowId === undefined
7831
7851
  ? {}
7832
7852
  : { initialContextWindowId: journal.contextWindowId }),
@@ -8285,136 +8305,66 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8285
8305
  const { claim, threadId } = session;
8286
8306
  const submissionId = claim.submissionId;
8287
8307
 
8288
- // The hint only selects this preparation. A real claim, current controls, exact
8289
- // evidence and checkpoint absence are verified under its owner before any reuse.
8290
- // No binding, instructions, model, Tool or cross-Thread operation runs in the window.
8291
- let prepared =
8292
- freshlyAdmitted && session.withInitialization !== undefined
8293
- ? yield* session.withInitialization(
8294
- Effect.gen(function* () {
8295
- const snapshot = yield* ledger.loadRecoverySnapshot(
8296
- RecoverySnapshotRequest.make({ submissionId }),
8297
- );
8308
+ // The hint selects a read under the existing owner. Only exact empty-Run evidence
8309
+ // permits startup; the initial commit still checks its tail and revision-zero CAS.
8310
+ const preparation = freshlyAdmitted ? yield* session.prepareStart ?? Effect.void : undefined;
8298
8311
 
8299
- const submission = snapshot.submission;
8300
-
8301
- if (
8302
- submission.state !== "ready" ||
8303
- submission.workerAdmission !== undefined ||
8304
- submission.messageAdmission !== undefined ||
8305
- submission.parentLinkage !== undefined ||
8306
- snapshot.inputApplied !== undefined ||
8307
- snapshot.abortIntent !== undefined ||
8308
- snapshot.approvalDecisions.length !== 0
8309
- )
8310
- return undefined;
8311
- yield* ensureThreadCreated(threadId, submission.agentId, submission.agentDigests);
8312
- yield* session.refresh;
8313
- const before = (yield* session.tail).sequence;
8314
-
8315
- const view = yield* recoveryView(
8316
- threadId,
8317
- before,
8318
- [submissionId],
8319
- runIdForSubmission(submissionId),
8320
- );
8321
-
8322
- if (
8323
- view.progress !== undefined ||
8324
- view.context !== undefined ||
8325
- view.operational.length !== 0 ||
8326
- view.records.some(({ record }) => record.payload._tag !== "ThreadCreated")
8327
- )
8328
- return undefined;
8329
- if (session.appendInput !== undefined) {
8330
- const captured = yield* PreparedAppend.capture(
8331
- AppendRequest.make({
8332
- threadId,
8333
- expectedTailSequence: before,
8334
- batch: CanonicalBatch.make({
8335
- batchId: submissionInputBatchId(submissionId),
8336
- producerId: config.producerId,
8337
- records: [yield* prepareOriginalInput(submission)],
8338
- }),
8339
- }),
8340
- );
8341
-
8342
- const record = captured.records[0]!.canonical;
8312
+ let prepared:
8313
+ | {
8314
+ snapshot: RecoverySnapshot;
8315
+ through: CanonicalSequence;
8316
+ view: Omit<Effect.Success<ReturnType<typeof recoveryView>>, "records"> & {
8317
+ readonly records: ReadonlyArray<CanonicalRecordEnvelope>;
8318
+ };
8319
+ start: Effect.Success<ReturnType<typeof makeRunStart>>;
8320
+ input: InitialContextInput;
8321
+ }
8322
+ | undefined;
8343
8323
 
8344
- if (!isOriginalInputRecord(record))
8345
- return yield* RunJournalError.make({
8346
- message: "Captured startup has no original input",
8347
- });
8348
- pendingOriginal = {
8349
- threadId,
8350
- sequence: CanonicalSequence.make(before + 1),
8351
- record,
8352
- };
8324
+ if (preparation !== undefined) {
8325
+ const { snapshot, identity } = preparation;
8326
+ const before = identity.tailSequence;
8353
8327
 
8354
- const start = yield* makeRunStart(
8355
- submission,
8356
- Duration.toMillis(registeredAgent.definition.policy.maxDuration),
8357
- view.records,
8358
- view.operational,
8359
- record,
8360
- ).pipe(Effect.provideService(CurrentRunWriter, session));
8328
+ const captured = yield* Effect.fromResult(
8329
+ captureRecord(yield* prepareOriginalInput(snapshot.submission)),
8330
+ ).pipe(
8331
+ Effect.mapError((cause) =>
8332
+ ThreadStoreError.make({
8333
+ operation: "capture startup input",
8334
+ message: cause.message,
8335
+ cause,
8336
+ }),
8337
+ ),
8338
+ );
8361
8339
 
8362
- return { snapshot, through: before, view, start, input: pendingOriginal };
8363
- }
8364
- const progress = progressWriters.get(session);
8340
+ const record = captured.canonical;
8365
8341
 
8366
- const applyInput = applyCanonicalInput(
8367
- session,
8368
- submission,
8369
- session,
8370
- view.records,
8371
- undefined,
8372
- );
8342
+ if (!isOriginalInputRecord(record))
8343
+ return yield* RunJournalError.make({ message: "Captured startup has no original input" });
8344
+ pendingOriginal = {
8345
+ threadId,
8346
+ sequence: CanonicalSequence.make(before + 1),
8347
+ record,
8348
+ };
8373
8349
 
8374
- yield* progress === undefined
8375
- ? applyInput
8376
- : progress
8377
- .withVerifiedEmptyRun(runIdForSubmission(submissionId), before, applyInput)
8378
- .pipe(Effect.provideService(CurrentRunWriter, promptSession));
8379
- const through = (yield* session.tail).sequence;
8380
- const added = yield* selectedRange(threadId, [submissionId], through, before);
8381
- const records = [...view.records, ...added];
8350
+ const view = {
8351
+ records: identity.records,
8352
+ context: undefined,
8353
+ progress: undefined,
8354
+ progressThrough: undefined,
8355
+ operational: [],
8356
+ };
8382
8357
 
8383
- const accepted = progressWriters
8384
- .get(session)
8385
- ?.acceptedCheckpoint(runIdForSubmission(submissionId));
8358
+ const start = yield* makeRunStart(
8359
+ snapshot.submission,
8360
+ Duration.toMillis(registeredAgent.definition.policy.maxDuration),
8361
+ view.records,
8362
+ view.operational,
8363
+ record,
8364
+ ).pipe(Effect.provideService(CurrentRunWriter, session));
8386
8365
 
8387
- if (
8388
- accepted === undefined ||
8389
- accepted.throughSequence !== through ||
8390
- accepted.progress.runId !== runIdForSubmission(submissionId) ||
8391
- accepted.progress.submissionId !== submissionId
8392
- )
8393
- return undefined;
8394
-
8395
- const start = yield* makeRunStart(
8396
- submission,
8397
- Duration.toMillis(registeredAgent.definition.policy.maxDuration),
8398
- records,
8399
- view.operational,
8400
- ).pipe(Effect.provideService(CurrentRunWriter, session));
8401
-
8402
- return {
8403
- snapshot,
8404
- through,
8405
- view: {
8406
- ...view,
8407
- records,
8408
- progress: accepted.progress,
8409
- progressThrough: accepted.throughSequence,
8410
- operational: accepted.operational,
8411
- },
8412
- start,
8413
- input: undefined,
8414
- };
8415
- }),
8416
- )
8417
- : undefined;
8366
+ prepared = { snapshot, through: before, view, start, input: pendingOriginal };
8367
+ }
8418
8368
 
8419
8369
  const preparedInput = prepared !== undefined;
8420
8370
 
@@ -8925,6 +8875,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8925
8875
  view.progressThrough,
8926
8876
  view.progress,
8927
8877
  view.context,
8878
+ view.operational,
8928
8879
  takeJournalMetadata(),
8929
8880
  lineage,
8930
8881
  approvalDecisionIntents,
@@ -9649,6 +9600,8 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
9649
9600
  for (const intent of intents) {
9650
9601
  const original = declared.get(intent.toolCallId);
9651
9602
 
9603
+ if (original !== undefined && nativeUpdateAccepted(submission, original, records)) continue;
9604
+
9652
9605
  if (
9653
9606
  original === undefined ||
9654
9607
  (current !== undefined &&
@@ -9830,9 +9783,52 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
9830
9783
  return yield* applyUnknownResolutionsForRecovery(snapshot, evidence, records);
9831
9784
  }
9832
9785
  case "AwaitUnknownResolution": {
9833
- // This Submission stays parked awaiting the authorized DUR-017 resolution path;
9834
- // the settlement obligation stays visible, nothing replays.
9835
- return "unknown";
9786
+ // Older Attempts may already have marked a native update unknown. Its exact
9787
+ // canonical acceptance is a factual resolution, never permission to retry an
9788
+ // external operation. The ledger wakes only when every unknown call is covered;
9789
+ // the next owner appends closure under the original call identity.
9790
+ const declared = yield* declaredCallsFor(
9791
+ records,
9792
+ runId,
9793
+ new Set(evidence.openToolCalls.map((call) => call.toolCallId)),
9794
+ );
9795
+
9796
+ let repaired = false;
9797
+
9798
+ for (const call of declared.values()) {
9799
+ if (
9800
+ snapshot.unknownResolutions.some((intent) => intent.toolCallId === call.toolCallId) ||
9801
+ !nativeUpdateAccepted(submission, call, records)
9802
+ )
9803
+ continue;
9804
+ yield* ledger
9805
+ .recordUnknownResolution(
9806
+ UnknownResolutionCommand.make({
9807
+ submissionId: submission.submissionId,
9808
+ toolCallId: call.toolCallId,
9809
+ author: RECONCILER_AUTHOR,
9810
+ reason: "The exact native update was canonically accepted",
9811
+ resolution: {
9812
+ _tag: "CompletedWithResult",
9813
+ result: { emitted: true },
9814
+ isFailure: false,
9815
+ },
9816
+ }),
9817
+ )
9818
+ .pipe(
9819
+ Effect.catchTag("UnknownResolutionConflict", (cause) =>
9820
+ LedgerError.make({
9821
+ operation: "recover native update",
9822
+ message: "Native acceptance conflicts with a retained resolution",
9823
+ cause,
9824
+ }),
9825
+ ),
9826
+ );
9827
+ repaired = true;
9828
+ }
9829
+ if (repaired) yield* wake.notify(submission.threadId);
9830
+
9831
+ return repaired ? "repaired" : "unknown";
9836
9832
  }
9837
9833
  case "AwaitApprovalDecision": {
9838
9834
  return yield* awaitApprovalForRecovery(snapshot, evidence, decision);
@@ -10486,8 +10482,11 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
10486
10482
 
10487
10483
  const factual = intent?.resolution;
10488
10484
 
10485
+ const acceptedNative =
10486
+ factual === undefined && (yield* updateRuntime.accepted(submission, selected.declared));
10487
+
10489
10488
  const reconciliation =
10490
- factual === undefined && selected.declared.executionKind === "ordinary"
10489
+ factual === undefined && !acceptedNative && selected.declared.executionKind === "ordinary"
10491
10490
  ? yield* reconciler
10492
10491
  .reconcile(
10493
10492
  DeclaredToolCallEvidence.make({
@@ -10505,9 +10504,11 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
10505
10504
  const completed =
10506
10505
  factual?._tag === "CompletedWithResult"
10507
10506
  ? factual
10508
- : Option.isSome(reconciliation) && reconciliation.value._tag === "CompletedWithResult"
10509
- ? reconciliation.value
10510
- : undefined;
10507
+ : acceptedNative
10508
+ ? { result: { emitted: true }, isFailure: false }
10509
+ : Option.isSome(reconciliation) && reconciliation.value._tag === "CompletedWithResult"
10510
+ ? reconciliation.value
10511
+ : undefined;
10511
10512
 
10512
10513
  const neverStarted =
10513
10514
  factual?._tag === "NeverHappened" ||
@@ -184,18 +184,25 @@ const captureFacts = (batch: CommitBatch) =>
184
184
  Result.gen(function* () {
185
185
  const inputs = batch.records;
186
186
 
187
- const { batchId, producerId } = validateBatchShape({
187
+ const {
188
+ batchId,
189
+ producerId,
190
+ records: slots,
191
+ } = validateBatchShape({
188
192
  batchId: batch.batchId,
189
193
  producerId: batch.producerId,
190
194
  records: inputs,
191
195
  });
192
196
 
193
- const encodings = yield* Result.all(inputs.map(captureRecord));
194
- const records = encodings.map((record) => record.canonical);
197
+ const first = yield* captureRecord(inputs[0]!);
198
+ const records: [RecordEnvelope, ...Array<RecordEnvelope>] = [first.canonical];
199
+
200
+ for (let index = 1; index < slots.length; index++)
201
+ records.push((yield* captureRecord(inputs[index]!)).canonical);
195
202
 
196
203
  return Object.freeze(
197
204
  CanonicalBatch.make(
198
- { batchId, producerId, records: [records[0]!, ...records.slice(1)] },
205
+ { batchId, producerId, records: Object.freeze(records) },
199
206
  { disableChecks: true },
200
207
  ),
201
208
  );
@@ -1646,25 +1653,30 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
1646
1653
  operational.set(fact.recordId, fact);
1647
1654
  }
1648
1655
 
1649
- const checkpoint = yield* ExecutionCheckpoint.makeEffect({
1650
- version: 2,
1651
- progressRecord: record,
1652
- operational: [...operational.values()],
1653
- canonicalRecords,
1654
- originalSequence:
1655
- originalSequence ??
1656
- CanonicalSequence.make(
1657
- after +
1658
- ownedRecords
1659
- .filter((fact) => !isOperationalRecord(fact))
1660
- .findIndex((fact) => fact.recordId === originalInput.recordId) +
1661
- 1,
1656
+ // The records above already belong to this writer. PreparedAppend captures the
1657
+ // complete update at the storage boundary, preserving their private encodings.
1658
+ const checkpoint = ExecutionCheckpoint.make(
1659
+ {
1660
+ version: 2,
1661
+ progressRecord: record,
1662
+ operational: [...operational.values()],
1663
+ canonicalRecords,
1664
+ originalSequence:
1665
+ originalSequence ??
1666
+ CanonicalSequence.make(
1667
+ after +
1668
+ ownedRecords
1669
+ .filter((fact) => !isOperationalRecord(fact))
1670
+ .findIndex((fact) => fact.recordId === originalInput.recordId) +
1671
+ 1,
1672
+ ),
1673
+ throughSequence: CanonicalSequence.make(
1674
+ after + ownedRecords.filter((fact) => !isOperationalRecord(fact)).length,
1662
1675
  ),
1663
- throughSequence: CanonicalSequence.make(
1664
- after + ownedRecords.filter((fact) => !isOperationalRecord(fact)).length,
1665
- ),
1666
- batchId: batch.batchId,
1667
- }).pipe(Effect.mapError((cause) => failure("Active execution exceeds its bounds", cause)));
1676
+ batchId: batch.batchId,
1677
+ },
1678
+ { disableChecks: true },
1679
+ );
1668
1680
 
1669
1681
  const state = {
1670
1682
  continuation,
@@ -1687,13 +1699,16 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
1687
1699
  );
1688
1700
  yield* checkFutureShapes(state);
1689
1701
  executions.push(
1690
- ExecutionUpdate.make({
1691
- previousRevision: previous?.continuation.revision ?? 0,
1692
- checkpoint,
1693
- facts: changed,
1694
- // Pending operations and handoffs retain their own recovery rows and original facts.
1695
- retire: position === "settled",
1696
- }),
1702
+ ExecutionUpdate.make(
1703
+ {
1704
+ previousRevision: previous?.continuation.revision ?? 0,
1705
+ checkpoint,
1706
+ facts: changed,
1707
+ // Pending operations and handoffs retain their own recovery rows and original facts.
1708
+ retire: position === "settled",
1709
+ },
1710
+ { disableChecks: true },
1711
+ ),
1697
1712
  );
1698
1713
  accepted.set(runId, state);
1699
1714
  }
@@ -1940,9 +1955,6 @@ export const makeProgressWriter = Effect.fnUntraced(function* (
1940
1955
  reserve,
1941
1956
  defer,
1942
1957
  check,
1943
- /** Internal read view immediately after this writer's acknowledged commit, while
1944
- * holding its initialization gates. Never authority across ownership or writes. */
1945
- acceptedCheckpoint: (runId: RunId) => cached.get(runId)?.checkpoint,
1946
1958
  /** Scope a verified empty execution/evidence view to one owned initialization body.
1947
1959
  * The caller holds progress+mutation gates; a changed writer or tail never reuses it. */
1948
1960
  withVerifiedEmptyRun: <A, E, R>(
@@ -17,6 +17,8 @@ import {
17
17
  type Claim,
18
18
  type ClaimRequest,
19
19
  type InputAppliedMarker,
20
+ type RecoverySnapshot,
21
+ RecoverySnapshotRequest,
20
22
  LedgerError,
21
23
  MarkInputAppliedRequest,
22
24
  MarkJoinedRequest,
@@ -34,6 +36,8 @@ import {
34
36
  type CommitBatch,
35
37
  type ExecutionUpdate,
36
38
  PreparedAppend,
39
+ FreshRunRead,
40
+ type ThreadIdentity,
37
41
  ThreadMaterialization,
38
42
  ThreadNotMaterialized,
39
43
  ThreadStore,
@@ -115,11 +119,12 @@ export interface RunStorageSession extends RunWriter, RunOwnership {
115
119
  readonly claim: Claim;
116
120
  /** Atomic original input/context plus the ledger marker, when the adapter supports it. */
117
121
  readonly appendInput?: RunWriter["append"];
118
- /** Library-only initialization, before application/model IO. Hold progress before mutation
119
- * so the captured controls and this owner's acknowledged input remain one read view. */
120
- readonly withInitialization?: <A, E, R>(
121
- effect: Effect.Effect<A, E, R>,
122
- ) => Effect.Effect<A, E | OwnershipLost, R>;
122
+ /** Read current controls, root identity and empty-Run evidence under this owner.
123
+ * Its tail is adopted by the writer; append still checks the tail and revision. */
124
+ readonly prepareStart?: Effect.Effect<
125
+ { readonly snapshot: RecoverySnapshot; readonly identity: ThreadIdentity } | undefined,
126
+ LedgerError | ThreadStoreFailure
127
+ >;
123
128
  readonly refresh: Effect.Effect<void, ThreadStoreFailure>;
124
129
  readonly publishSettlement: (
125
130
  batch: CanonicalBatch,
@@ -182,14 +187,12 @@ const makeWriter = Effect.fnUntraced(function* (threadId: ThreadId) {
182
187
  const publisher = yield* ThreadStore;
183
188
 
184
189
  const append: RunWriter["append"] = Effect.fnUntraced(function* (batch, executions) {
185
- const captured = yield* PreparedAppend.capture(
186
- AppendRequest.make({
187
- threadId,
188
- expectedTailSequence: tail.sequence,
189
- batch,
190
- ...(executions === undefined ? {} : { executions }),
191
- }),
192
- ).pipe(
190
+ const captured = yield* PreparedAppend.capture({
191
+ threadId,
192
+ expectedTailSequence: tail.sequence,
193
+ batch,
194
+ ...(executions === undefined ? {} : { executions }),
195
+ }).pipe(
193
196
  Effect.mapError((cause) =>
194
197
  ThreadStoreError.make({
195
198
  operation: "capture append",
@@ -343,8 +346,46 @@ export const make = Effect.gen(function* () {
343
346
  ...writer,
344
347
  claim: claimed,
345
348
  ...(appendInput === undefined ? {} : { appendInput }),
346
- withInitialization: (effect) =>
347
- owner.withProgress(request.threadId, generation.use(effect)),
349
+ ...(store.readFreshRun === undefined || appendInput === undefined
350
+ ? {}
351
+ : {
352
+ prepareStart: owner.withProgress(
353
+ request.threadId,
354
+ generation.use(
355
+ Effect.gen(function* () {
356
+ const snapshot = yield* ledger.loadRecoverySnapshot(
357
+ RecoverySnapshotRequest.make({ submissionId: claimed.submissionId }),
358
+ );
359
+
360
+ const submission = snapshot.submission;
361
+
362
+ if (
363
+ submission.threadId !== request.threadId ||
364
+ submission.state !== "ready" ||
365
+ submission.workerAdmission !== undefined ||
366
+ submission.messageAdmission !== undefined ||
367
+ submission.parentLinkage !== undefined ||
368
+ snapshot.inputApplied !== undefined ||
369
+ snapshot.abortIntent !== undefined ||
370
+ snapshot.approvalDecisions.length !== 0
371
+ )
372
+ return undefined;
373
+
374
+ const identity = yield* store.readFreshRun!(
375
+ FreshRunRead.make({
376
+ threadId: request.threadId,
377
+ submissionId: claimed.submissionId,
378
+ }),
379
+ );
380
+
381
+ if (Option.isNone(identity)) return undefined;
382
+ adoptTail(identity.value.tailSequence);
383
+
384
+ return { snapshot, identity: identity.value };
385
+ }),
386
+ ),
387
+ ),
388
+ }),
348
389
  release: generation.release,
349
390
  refresh: writer.refresh,
350
391
  markInputApplied: (marker) =>
@@ -836,6 +836,11 @@ export class ThreadIdentityRequest extends Schema.Class<ThreadIdentityRequest>(
836
836
  "@effect-agent/thread/ThreadIdentityRequest",
837
837
  )({ threadId: ThreadId }) {}
838
838
 
839
+ export class FreshRunRead extends Schema.Class<FreshRunRead>("@effect-agent/thread/FreshRunRead")({
840
+ threadId: ThreadId,
841
+ submissionId: SubmissionId,
842
+ }) {}
843
+
839
844
  /**
840
845
  * One consistent snapshot: Thread ID, canonical tail, admission presence, first record,
841
846
  * exact worker origin, then exact subagent lineage. A row selected twice appears only
@@ -1246,6 +1251,12 @@ export class ThreadStore extends Context.Service<
1246
1251
  readonly readIdentity: (
1247
1252
  request: ThreadIdentityRequest,
1248
1253
  ) => Effect.Effect<ThreadIdentity, ThreadStoreError | ThreadNotMaterialized>;
1254
+ /** Owner-held preparation for an admitted root Run. Some proves an initialized root
1255
+ * identity and no checkpoint, Run membership or exact input/abort/settlement record.
1256
+ * None requires ordinary recovery; it never authorizes overwriting existing evidence. */
1257
+ readonly readFreshRun?: (
1258
+ request: FreshRunRead,
1259
+ ) => Effect.Effect<Option.Option<ThreadIdentity>, ThreadStoreError | ThreadNotMaterialized>;
1249
1260
  readonly readWorkerCapacity?: (
1250
1261
  request: ThreadWorkerCapacityRequest,
1251
1262
  ) => Effect.Effect<ThreadWorkerCapacity, ThreadStoreError | ThreadNotMaterialized>;