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

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 (191) hide show
  1. package/dist/{Admin-Qa3I1oA5.d.mts → Admin-Bpg24yCK.d.mts} +19 -13
  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-CPlw5_7e.mjs → DurableAgentRuntime-CGW93k81.mjs} +176 -63
  10. package/dist/DurableAgentRuntime-CGW93k81.mjs.map +1 -0
  11. package/dist/{DurableStep-DXGn7KQ4.d.mts → DurableStep-CAJnlgfL.d.mts} +5 -4
  12. package/dist/{EventSource-BTu68yDW.d.mts → EventSource-A6TB7t-f.d.mts} +2 -2
  13. package/dist/{MessageDelivery-DjAZJ4Fd.d.mts → MessageDelivery-BkWrcQUd.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-wgY4JMZY.d.mts → PreparedInputAdmission-DKIfqRZT.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-3jB5pULC.d.mts → RunContinuation-Ce2pR8VD.d.mts} +4 -4
  22. package/dist/{RunContinuation-BiyKJK32.mjs → RunContinuation-D42RFqjS.mjs} +5 -5
  23. package/dist/RunContinuation-D42RFqjS.mjs.map +1 -0
  24. package/dist/{RunJournal-CPMKcfd0.mjs → RunJournal-oJLo-pjS.mjs} +7 -7
  25. package/dist/{RunJournal-CPMKcfd0.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-CzutHJBE.mjs → RunStorage-BRGP3Tcu.mjs} +43 -33
  28. package/dist/RunStorage-BRGP3Tcu.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-DmIHlOJK.d.mts → Subscription-D5sOrmlI.d.mts} +2 -2
  36. package/dist/{SubscriptionInput-DgcQhvbe.d.mts → SubscriptionInput-CxSXZUiC.d.mts} +2 -2
  37. package/dist/{ThreadImport-DP-vOk2F.d.mts → ThreadImport-C6IiPJMW.d.mts} +42 -42
  38. package/dist/{ThreadImport-CjlG57vH.mjs → ThreadImport-DUcPj5jC.mjs} +9 -9
  39. package/dist/{ThreadImport-CjlG57vH.mjs.map → ThreadImport-DUcPj5jC.mjs.map} +1 -1
  40. package/dist/{ThreadStore-EuUilthA.mjs → ThreadStore-Cn6FDWX9.mjs} +42 -21
  41. package/dist/ThreadStore-Cn6FDWX9.mjs.map +1 -0
  42. package/dist/{ThreadTransfer-DB_zsrtJ.mjs → ThreadTransfer-BWnAHIge.mjs} +4 -4
  43. package/dist/{ThreadTransfer-DB_zsrtJ.mjs.map → ThreadTransfer-BWnAHIge.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-eBeXt_mu.mjs → WorkerAdmission-cfiK9aRi.mjs} +6 -6
  48. package/dist/{WorkerAdmission-eBeXt_mu.mjs.map → WorkerAdmission-cfiK9aRi.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/CodeMode.mjs +1 -1
  52. package/dist/capabilities/Commands.d.mts +1 -1
  53. package/dist/capabilities/ContextTools.mjs +1 -1
  54. package/dist/capabilities/McpClient.mjs +1 -1
  55. package/dist/capabilities/MemoryNotes.d.mts +1 -1
  56. package/dist/capabilities/MemoryNotes.mjs +2 -1
  57. package/dist/capabilities/MemoryNotes.mjs.map +1 -1
  58. package/dist/capabilities/Messaging.d.mts +1 -1
  59. package/dist/capabilities/Messaging.mjs +2 -2
  60. package/dist/capabilities/RunHooks.d.mts +1 -1
  61. package/dist/capabilities/Subagent.d.mts +2 -2
  62. package/dist/capabilities/Subagent.mjs +2 -2
  63. package/dist/capabilities/ToolDiscovery.mjs +1 -1
  64. package/dist/capabilities/WebCapture.mjs +1 -1
  65. package/dist/capabilities/WebSearch.mjs +1 -1
  66. package/dist/core/Agent.mjs +1 -1
  67. package/dist/core/Worker.d.mts +1 -1
  68. package/dist/core/Worker.mjs +1 -1
  69. package/dist/durable/ActivityStore.mjs +1 -1
  70. package/dist/durable/Admin.d.mts +1 -1
  71. package/dist/durable/Admin.mjs +1 -1
  72. package/dist/durable/AgentRegistration.d.mts +1 -1
  73. package/dist/durable/AgentRegistration.mjs +1 -1
  74. package/dist/durable/Certification.d.mts +1 -1
  75. package/dist/durable/CommittedActivity.d.mts +1 -1
  76. package/dist/durable/CommittedActivity.mjs +3 -3
  77. package/dist/durable/Digest.mjs +1 -1
  78. package/dist/durable/DurableAgentRuntime.d.mts +1 -1
  79. package/dist/durable/DurableAgentRuntime.mjs +2 -2
  80. package/dist/durable/EventSource.d.mts +1 -1
  81. package/dist/durable/EventSource.mjs +1 -1
  82. package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
  83. package/dist/durable/LifecyclePublication.d.mts +1 -1
  84. package/dist/durable/LifecyclePublication.mjs +3 -3
  85. package/dist/durable/MessageDelivery.d.mts +1 -1
  86. package/dist/durable/MessageDelivery.mjs +3 -3
  87. package/dist/durable/MessageDeliveryStoreConformance.d.mts +2 -2
  88. package/dist/durable/MessageDeliveryStoreConformance.mjs +3 -3
  89. package/dist/durable/PersistentHistory.d.mts +1 -1
  90. package/dist/durable/PersistentHistory.mjs +4 -4
  91. package/dist/durable/PreparedInputAdmission.d.mts +1 -1
  92. package/dist/durable/RecordFormat.mjs +1 -1
  93. package/dist/durable/Records.mjs +1 -1
  94. package/dist/durable/Recovery.d.mts +1 -1
  95. package/dist/durable/Recovery.mjs +1 -1
  96. package/dist/durable/RunContinuation.d.mts +2 -2
  97. package/dist/durable/RunContinuation.mjs +3 -3
  98. package/dist/durable/RunJournal.d.mts +1 -1
  99. package/dist/durable/RunJournal.mjs +1 -1
  100. package/dist/durable/RunStorage.d.mts +1 -1
  101. package/dist/durable/RunStorage.mjs +1 -1
  102. package/dist/durable/Schedule.mjs +1 -1
  103. package/dist/durable/ScheduleStoreConformance.mjs +1 -1
  104. package/dist/durable/ScheduleTransition.mjs +1 -1
  105. package/dist/durable/Scheduling.d.mts +1 -1
  106. package/dist/durable/Scheduling.mjs +1 -1
  107. package/dist/durable/SettlementPublisher.d.mts +1 -1
  108. package/dist/durable/SettlementPublisher.mjs +3 -3
  109. package/dist/durable/SubmissionLedger.d.mts +1 -1
  110. package/dist/durable/SubmissionLedger.mjs +4 -4
  111. package/dist/durable/SubmissionLedger.mjs.map +1 -1
  112. package/dist/durable/SubmissionLedgerConformance.d.mts +1 -1
  113. package/dist/durable/SubmissionLedgerConformance.mjs +7 -7
  114. package/dist/durable/SubmissionStatus.d.mts +1 -1
  115. package/dist/durable/Subscription.d.mts +1 -1
  116. package/dist/durable/Subscription.mjs +2 -2
  117. package/dist/durable/SubscriptionInput.d.mts +1 -1
  118. package/dist/durable/SubscriptionInput.mjs +2 -2
  119. package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
  120. package/dist/durable/SubscriptionStoreConformance.mjs +1 -1
  121. package/dist/durable/SubscriptionTools.d.mts +3 -3
  122. package/dist/durable/SubscriptionTools.mjs +2 -1
  123. package/dist/durable/SubscriptionTools.mjs.map +1 -1
  124. package/dist/durable/SubscriptionTransition.d.mts +1 -1
  125. package/dist/durable/SubscriptionTransition.mjs +1 -1
  126. package/dist/durable/Subscriptions.d.mts +5 -5
  127. package/dist/durable/Subscriptions.mjs +2 -2
  128. package/dist/durable/ThreadArchiveRange.d.mts +1 -1
  129. package/dist/durable/ThreadArchiveRange.mjs +1 -1
  130. package/dist/durable/ThreadContextHistory.d.mts +1 -1
  131. package/dist/durable/ThreadContextHistory.mjs +2 -2
  132. package/dist/durable/ThreadContextHistoryProjection.mjs +1 -1
  133. package/dist/durable/ThreadImport.d.mts +1 -1
  134. package/dist/durable/ThreadImport.mjs +1 -1
  135. package/dist/durable/ThreadInvariants.d.mts +3 -3
  136. package/dist/durable/ThreadInvariants.mjs +4 -4
  137. package/dist/durable/ThreadProjection.mjs +1 -1
  138. package/dist/durable/ThreadProjectionMaintenance.d.mts +1 -1
  139. package/dist/durable/ThreadReader.d.mts +1 -1
  140. package/dist/durable/ThreadReader.mjs +1 -1
  141. package/dist/durable/ThreadStore.d.mts +1 -1
  142. package/dist/durable/ThreadStore.mjs +2 -2
  143. package/dist/durable/ThreadStoreConformance.d.mts +1 -1
  144. package/dist/durable/ThreadStoreConformance.mjs +4 -4
  145. package/dist/durable/ThreadTransfer.d.mts +1 -1
  146. package/dist/durable/ThreadTransfer.mjs +1 -1
  147. package/dist/durable/ThreadWork.d.mts +1 -1
  148. package/dist/durable/ThreadWork.mjs +5 -5
  149. package/dist/durable/ToolReconciler.mjs +1 -1
  150. package/dist/durable/WorkerAdmission.d.mts +68 -68
  151. package/dist/durable/WorkerAdmission.mjs +1 -1
  152. package/dist/durable/WorkerHost.d.mts +2 -2
  153. package/dist/durable/WorkerHost.mjs +1 -1
  154. package/dist/engine/AgentRuntime.d.mts +1 -1
  155. package/dist/engine/AgentRuntime.mjs +1 -1
  156. package/dist/engine/DurableStep.d.mts +2 -2
  157. package/dist/engine/DurableStep.mjs +1 -11
  158. package/dist/engine/DurableStep.mjs.map +1 -1
  159. package/dist/engine/MessagingHost.d.mts +1 -1
  160. package/dist/engine/MessagingHost.mjs +1 -1
  161. package/dist/engine/RunOptions.d.mts +1 -1
  162. package/dist/engine/SubagentHost.d.mts +1 -1
  163. package/dist/engine/SubagentHost.mjs +1 -1
  164. package/dist/index.d.mts +16 -16
  165. package/dist/index.mjs +15 -15
  166. package/dist/{run-context-reader-DVhJZ1Qe.d.mts → run-context-reader-BtBPX_nC.d.mts} +2 -2
  167. package/dist/tool-execution-Ba7tO7Pt.mjs +17 -0
  168. package/dist/tool-execution-Ba7tO7Pt.mjs.map +1 -0
  169. package/package.json +1 -1
  170. package/src/core/Worker.ts +3 -1
  171. package/src/core/internal/agent-updates.ts +9 -1
  172. package/src/core/internal/tool-execution.ts +33 -0
  173. package/src/durable/DurableAgentRuntime.ts +243 -63
  174. package/src/durable/RunContinuation.ts +2 -2
  175. package/src/durable/RunJournal.ts +9 -5
  176. package/src/durable/RunStorage.ts +83 -61
  177. package/src/durable/SubmissionLedger.ts +8 -0
  178. package/src/durable/ThreadStore.ts +39 -19
  179. package/src/durable/internal/agent-updates.ts +59 -3
  180. package/src/durable/internal/initial-context.ts +17 -2
  181. package/src/durable/internal/prompt-history-cache.ts +13 -8
  182. package/src/durable/internal/worker-host.ts +3 -1
  183. package/src/engine/DurableStep.ts +5 -31
  184. package/src/engine/internal/agent-runtime.ts +2 -1
  185. package/dist/Agent-BiRbr73L.mjs.map +0 -1
  186. package/dist/AgentRuntime-DaDKMasp.mjs.map +0 -1
  187. package/dist/DurableAgentRuntime-CPlw5_7e.mjs.map +0 -1
  188. package/dist/RunContinuation-BiyKJK32.mjs.map +0 -1
  189. package/dist/RunStorage-CzutHJBE.mjs.map +0 -1
  190. package/dist/ThreadStore-EuUilthA.mjs.map +0 -1
  191. package/dist/Worker-DZjdMjZn.mjs.map +0 -1
@@ -156,9 +156,9 @@ 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
- import { initialContext } from "./internal/initial-context.ts";
161
+ import { initialContext, type InitialContextInput } from "./internal/initial-context.ts";
162
162
  import {
163
163
  makeJournalMetadata,
164
164
  type JournalMetadata,
@@ -403,6 +403,9 @@ import {
403
403
  getRunInput,
404
404
  ThreadReader,
405
405
  MAX_THREAD_EXPORT_PAGE_BYTES,
406
+ PreparedAppend,
407
+ type CommitBatch,
408
+ type ExecutionUpdate,
406
409
  } from "./ThreadStore.ts";
407
410
  import {
408
411
  type WorkIndexRebuildRequest,
@@ -594,6 +597,11 @@ export { threadCreatedBatchId, threadCreatedRecordId } from "./internal/thread-i
594
597
  export const recoveryRepairBatchId = (submissionId: SubmissionId, decisionTag: string): BatchId =>
595
598
  decodeBatchId(`repair:${submissionId}:${decisionTag}`);
596
599
 
600
+ const isOriginalInputRecord = (
601
+ record: RecordEnvelope,
602
+ ): record is RecordEnvelope & { readonly payload: UserInputRecorded } =>
603
+ record.payload._tag === "UserInputRecorded";
604
+
597
605
  /** Deterministic record identity of one executed recovery decision's `RepairAnnotated` record. */
598
606
  export const recoveryRepairRecordId = (submissionId: SubmissionId, decisionTag: string): RecordId =>
599
607
  decodeRecordId(`repair:${submissionId}:${decisionTag}`);
@@ -1364,7 +1372,7 @@ interface OpenCallReview {
1364
1372
 
1365
1373
  interface InitialJournalSource {
1366
1374
  records: ReadonlyArray<JournalRecordEnvelope> | undefined;
1367
- readonly original: CanonicalRecordEnvelope;
1375
+ readonly original: InitialContextInput;
1368
1376
  readonly suffix: ReadonlyArray<CanonicalRecordEnvelope>;
1369
1377
  cacheable: boolean;
1370
1378
  readonly prefix?: CachedPromptHistory;
@@ -1472,7 +1480,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
1472
1480
 
1473
1481
  // Rebuild the pinned admission and captured suffix using this runtime's host dependencies.
1474
1482
  const readInitialJournal = (
1475
- original: CanonicalRecordEnvelope,
1483
+ original: InitialContextInput,
1476
1484
  suffix: ReadonlyArray<CanonicalRecordEnvelope>,
1477
1485
  ) =>
1478
1486
  initialContext(original).pipe(
@@ -2617,7 +2625,10 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
2617
2625
  Effect.map(({ owned }) => owned),
2618
2626
  );
2619
2627
 
2620
- const withProgressSession = Effect.fnUntraced(function* (session: RunStorageSession) {
2628
+ const withProgressSession = Effect.fnUntraced(function* (
2629
+ session: RunStorageSession,
2630
+ originalInput?: () => InitialContextInput | undefined,
2631
+ ) {
2621
2632
  const { owned, progress } = yield* withProgress(session);
2622
2633
 
2623
2634
  activeProgress.set(session.threadId, { writer: progress });
@@ -2628,9 +2639,44 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
2628
2639
  }),
2629
2640
  );
2630
2641
 
2642
+ const inputWriter =
2643
+ session.appendInput === undefined
2644
+ ? undefined
2645
+ : {
2646
+ ...session,
2647
+ append: session.appendInput,
2648
+ };
2649
+
2631
2650
  const wrapped: RunStorageSession = {
2632
2651
  ...session,
2633
2652
  append: owned.append,
2653
+ ...(inputWriter === undefined
2654
+ ? {}
2655
+ : {
2656
+ appendInput: (batch: CommitBatch) =>
2657
+ storageOwner.withProgress(
2658
+ session.threadId,
2659
+ storageOwner.withMutation(
2660
+ Effect.gen(function* () {
2661
+ yield* session.checkActive;
2662
+ // The captured empty canonical prefix is enforced again by the append tail and
2663
+ // checkpoint revision-zero CAS. It is not a cache entry across preparation IO.
2664
+ const original = originalInput?.();
2665
+ const commit = progress.commit(batch);
2666
+
2667
+ return yield* (
2668
+ original === undefined
2669
+ ? commit
2670
+ : progress.withVerifiedEmptyRun(
2671
+ runIdForSubmission(session.claim.submissionId),
2672
+ CanonicalSequence.make(original.sequence - 1),
2673
+ commit,
2674
+ )
2675
+ ).pipe(Effect.provideService(CurrentRunWriter, inputWriter));
2676
+ }),
2677
+ ),
2678
+ ),
2679
+ }),
2634
2680
  publishSettlement: (batch) =>
2635
2681
  progress.publish(batch).pipe(Effect.provideService(CurrentRunSettlement, session)),
2636
2682
  };
@@ -3048,6 +3094,22 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
3048
3094
  recovered += 1;
3049
3095
  });
3050
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
+ }
3051
3113
  if (intent !== undefined) {
3052
3114
  switch (intent.resolution._tag) {
3053
3115
  case "AbortSubmission":
@@ -3167,6 +3229,20 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
3167
3229
  );
3168
3230
  });
3169
3231
 
3232
+ const prepareOriginalInput = (submission: SubmissionSnapshot) =>
3233
+ makeEnvelope(
3234
+ submissionInputRecordId(submission.submissionId),
3235
+ UserInputRecorded.make({
3236
+ submissionId: submission.submissionId,
3237
+ kind: "user",
3238
+ runId: runIdForSubmission(submission.submissionId),
3239
+ input: submission.inputPayload,
3240
+ ...(submission.messageAdmission === undefined
3241
+ ? {}
3242
+ : { messageAdmission: submission.messageAdmission }),
3243
+ }),
3244
+ );
3245
+
3170
3246
  /**
3171
3247
  * Plan step 2: append the deterministic `UserInputRecorded` record (batch idempotency makes it
3172
3248
  * exactly-once canonical, DUR-007) and mark it applied. When canonical history already carries
@@ -3192,18 +3268,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
3192
3268
  return;
3193
3269
  }
3194
3270
 
3195
- const envelope = yield* makeEnvelope(
3196
- recordId,
3197
- UserInputRecorded.make({
3198
- submissionId,
3199
- kind: "user",
3200
- runId: runIdForSubmission(submissionId),
3201
- input: submission.inputPayload,
3202
- ...(submission.messageAdmission === undefined
3203
- ? {}
3204
- : { messageAdmission: submission.messageAdmission }),
3205
- }),
3206
- );
3271
+ const envelope = yield* prepareOriginalInput(submission);
3207
3272
 
3208
3273
  const result = yield* appendBatch(
3209
3274
  ctx,
@@ -3254,8 +3319,13 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
3254
3319
  maxDurationMillis: number,
3255
3320
  records: ReadonlyArray<CanonicalRecordEnvelope>,
3256
3321
  operational: ReadonlyArray<RecordEnvelope>,
3322
+ input?: RecordEnvelope,
3257
3323
  ) {
3258
3324
  const writer = yield* CurrentRunWriter;
3325
+ const append = input === undefined ? writer.append : writer.appendInput;
3326
+
3327
+ if (append === undefined)
3328
+ return yield* RunJournalError.make({ message: "Fresh startup requires an input publisher" });
3259
3329
  const runId = runIdForSubmission(submission.submissionId);
3260
3330
  const recordId = runStartedRecordId(runId);
3261
3331
  const existing = yield* readRunStart(submission.threadId, runId, operational);
@@ -3304,13 +3374,21 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
3304
3374
  }
3305
3375
  yield* hit("run:before-start-append");
3306
3376
  yield* appendBatch(
3307
- writer,
3377
+ { threadId: writer.threadId, append },
3308
3378
  CanonicalBatch.make({
3309
- batchId: runStartedBatchId(runId),
3379
+ batchId:
3380
+ input === undefined
3381
+ ? runStartedBatchId(runId)
3382
+ : submissionInputBatchId(submission.submissionId),
3310
3383
  producerId: config.producerId,
3311
- records: [start, ...(context === undefined ? [] : [context])],
3384
+ records: [
3385
+ input ?? start,
3386
+ ...(input === undefined ? [] : [start]),
3387
+ ...(context === undefined ? [] : [context]),
3388
+ ],
3312
3389
  }),
3313
3390
  );
3391
+ if (input !== undefined) yield* hit("input:after-canonical-append");
3314
3392
  committed = true;
3315
3393
  yield* hit("run:after-start-append");
3316
3394
  });
@@ -4856,12 +4934,14 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
4856
4934
  // Unrelated Thread traffic does not invalidate an already validated owner projection.
4857
4935
  const projectionThrough = Math.max(progressThrough ?? 0, records.at(-1)?.sequence ?? 0);
4858
4936
 
4859
- const originalInput = records.find(
4860
- ({ record: { payload } }) =>
4861
- payload._tag === "UserInputRecorded" &&
4862
- payload.kind === "user" &&
4863
- payload.submissionId === submissionId,
4864
- );
4937
+ const originalInput =
4938
+ initialJournal?.original ??
4939
+ records.find(
4940
+ ({ record: { payload } }) =>
4941
+ payload._tag === "UserInputRecorded" &&
4942
+ payload.kind === "user" &&
4943
+ payload.submissionId === submissionId,
4944
+ );
4865
4945
 
4866
4946
  if (originalInput === undefined)
4867
4947
  return yield* RunJournalError.make({ message: "Run has no original context boundary" });
@@ -5447,18 +5527,6 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
5447
5527
  usageSummary: yield* currentUsageSummary(),
5448
5528
  };
5449
5529
  }
5450
- // Summaries cover only prior Runs. Pruning and rollover also map fully settled
5451
- // current-Run records and preserves the canonical instruction/input block during replay.
5452
- let ownerFirstSequence: CanonicalSequence | undefined;
5453
-
5454
- for (const envelope of records) {
5455
- const payload = envelope.record.payload;
5456
-
5457
- if ("runId" in payload && payload.runId === runId) {
5458
- ownerFirstSequence = envelope.sequence;
5459
- break;
5460
- }
5461
- }
5462
5530
 
5463
5531
  /** Only canonical joined inputs can require restoration from an earlier Attempt. */
5464
5532
  let joinBacklog: ReadonlyArray<JoinSnapshot> | undefined =
@@ -5839,6 +5907,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
5839
5907
  const start = yield* CurrentRunStart;
5840
5908
 
5841
5909
  yield* start.commit(yield* makeEnvelope(recordId, payload));
5910
+ knownIds.add(originalInput.record.recordId);
5842
5911
  knownIds.add(runStartedRecordId(runId));
5843
5912
  knownIds.add(recordId);
5844
5913
  historyEvidence.clear();
@@ -6400,13 +6469,10 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
6400
6469
  );
6401
6470
  }
6402
6471
 
6403
- // Summaries use the initial prior-Run boundaries; pruning and rollover also admit
6404
- // complete current-Run boundaries from the fresh canonical source above.
6472
+ // The validated original input bounds summaries even when startup deferred its append.
6473
+ // Pruning and rollover also admit complete current-Run canonical boundaries.
6405
6474
  const coverable = sourceBoundaries.filter(
6406
- (boundary) =>
6407
- commit.kind !== "summarize" ||
6408
- ownerFirstSequence === undefined ||
6409
- boundary.sequence < ownerFirstSequence,
6475
+ (boundary) => commit.kind !== "summarize" || boundary.sequence < originalInput.sequence,
6410
6476
  );
6411
6477
 
6412
6478
  if (coverable.length === 0) {
@@ -8164,6 +8230,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8164
8230
  // before suspension; only acknowledged ranges enter this Attempt's disposable suffix.
8165
8231
  let committedPromptSuffix: CommittedPromptSuffix | undefined;
8166
8232
  const storageSession = session;
8233
+ let pendingOriginal: InitialContextInput | undefined;
8167
8234
 
8168
8235
  yield* Effect.addFinalizer(() =>
8169
8236
  Effect.sync(() => {
@@ -8174,6 +8241,27 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8174
8241
 
8175
8242
  const promptSession: RunStorageSession = {
8176
8243
  ...storageSession,
8244
+ ...(storageSession.appendInput === undefined
8245
+ ? {}
8246
+ : {
8247
+ appendInput: (batch: CommitBatch, executions?: ReadonlyArray<ExecutionUpdate>) =>
8248
+ storageSession.appendInput!(batch, executions).pipe(
8249
+ Effect.tap((result) =>
8250
+ Effect.sync(() => {
8251
+ if (
8252
+ pendingOriginal !== undefined &&
8253
+ !result.replayed &&
8254
+ result.firstSequence === pendingOriginal.sequence
8255
+ )
8256
+ committedPromptSuffix = makeCommittedPromptSuffix({
8257
+ threadId: storageSession.threadId,
8258
+ sequence: result.firstSequence,
8259
+ record: batch.records[0]!,
8260
+ });
8261
+ }),
8262
+ ),
8263
+ ),
8264
+ }),
8177
8265
  append: (batch, executions) => {
8178
8266
  const suffix = committedPromptSuffix;
8179
8267
  const append = storageSession.append(batch, executions);
@@ -8209,7 +8297,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8209
8297
  },
8210
8298
  };
8211
8299
 
8212
- session = yield* withProgressSession(promptSession);
8300
+ session = yield* withProgressSession(promptSession, () => pendingOriginal);
8213
8301
  const { claim, threadId } = session;
8214
8302
  const submissionId = claim.submissionId;
8215
8303
 
@@ -8254,6 +8342,41 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8254
8342
  view.records.some(({ record }) => record.payload._tag !== "ThreadCreated")
8255
8343
  )
8256
8344
  return undefined;
8345
+ if (session.appendInput !== undefined) {
8346
+ const captured = yield* PreparedAppend.capture(
8347
+ AppendRequest.make({
8348
+ threadId,
8349
+ expectedTailSequence: before,
8350
+ batch: CanonicalBatch.make({
8351
+ batchId: submissionInputBatchId(submissionId),
8352
+ producerId: config.producerId,
8353
+ records: [yield* prepareOriginalInput(submission)],
8354
+ }),
8355
+ }),
8356
+ );
8357
+
8358
+ const record = captured.records[0]!.canonical;
8359
+
8360
+ if (!isOriginalInputRecord(record))
8361
+ return yield* RunJournalError.make({
8362
+ message: "Captured startup has no original input",
8363
+ });
8364
+ pendingOriginal = {
8365
+ threadId,
8366
+ sequence: CanonicalSequence.make(before + 1),
8367
+ record,
8368
+ };
8369
+
8370
+ const start = yield* makeRunStart(
8371
+ submission,
8372
+ Duration.toMillis(registeredAgent.definition.policy.maxDuration),
8373
+ view.records,
8374
+ view.operational,
8375
+ record,
8376
+ ).pipe(Effect.provideService(CurrentRunWriter, session));
8377
+
8378
+ return { snapshot, through: before, view, start, input: pendingOriginal };
8379
+ }
8257
8380
  const progress = progressWriters.get(session);
8258
8381
 
8259
8382
  const applyInput = applyCanonicalInput(
@@ -8303,6 +8426,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8303
8426
  operational: accepted.operational,
8304
8427
  },
8305
8428
  start,
8429
+ input: undefined,
8306
8430
  };
8307
8431
  }),
8308
8432
  )
@@ -8737,12 +8861,14 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8737
8861
  let initialJournal: InitialJournalSource | undefined;
8738
8862
 
8739
8863
  if (view.context === undefined) {
8740
- const original = currentRecords.find(
8741
- ({ record }) =>
8742
- record.payload._tag === "UserInputRecorded" &&
8743
- record.payload.kind === "user" &&
8744
- record.payload.submissionId === submissionId,
8745
- );
8864
+ const original =
8865
+ initialization?.input ??
8866
+ currentRecords.find(
8867
+ ({ record }) =>
8868
+ record.payload._tag === "UserInputRecorded" &&
8869
+ record.payload.kind === "user" &&
8870
+ record.payload.submissionId === submissionId,
8871
+ );
8746
8872
 
8747
8873
  if (original === undefined)
8748
8874
  return yield* RunJournalError.make({
@@ -8752,7 +8878,10 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8752
8878
  const suffix = currentRecords.filter((entry) => entry.sequence > original.sequence);
8753
8879
 
8754
8880
  const fresh =
8755
- !lineage.inputWasRecorded && tail.sequence === original.sequence && suffix.length === 0;
8881
+ initialization?.input !== undefined ||
8882
+ (!lineage.inputWasRecorded &&
8883
+ tail.sequence === original.sequence &&
8884
+ suffix.length === 0);
8756
8885
 
8757
8886
  // Every replay stays bounded at the ORIGINAL admission, never the later Thread tail.
8758
8887
  const source: InitialJournalSource = yield* Effect.gen(function* () {
@@ -8795,9 +8924,10 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8795
8924
  }
8796
8925
 
8797
8926
  committedPromptSuffix?.discard();
8798
- committedPromptSuffix = initialJournal?.cacheable
8799
- ? makeCommittedPromptSuffix(initialJournal.original)
8800
- : undefined;
8927
+ committedPromptSuffix =
8928
+ initialJournal?.cacheable && initialization?.input === undefined
8929
+ ? makeCommittedPromptSuffix(initialJournal.original)
8930
+ : undefined;
8801
8931
 
8802
8932
  const outcome = yield* runModel(
8803
8933
  agent,
@@ -8807,7 +8937,7 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
8807
8937
  currentRecords,
8808
8938
  canonical,
8809
8939
  initialJournal,
8810
- tail.sequence,
8940
+ initialization?.input?.sequence ?? tail.sequence,
8811
8941
  view.progressThrough,
8812
8942
  view.progress,
8813
8943
  view.context,
@@ -9535,6 +9665,8 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
9535
9665
  for (const intent of intents) {
9536
9666
  const original = declared.get(intent.toolCallId);
9537
9667
 
9668
+ if (original !== undefined && nativeUpdateAccepted(submission, original, records)) continue;
9669
+
9538
9670
  if (
9539
9671
  original === undefined ||
9540
9672
  (current !== undefined &&
@@ -9716,9 +9848,52 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
9716
9848
  return yield* applyUnknownResolutionsForRecovery(snapshot, evidence, records);
9717
9849
  }
9718
9850
  case "AwaitUnknownResolution": {
9719
- // This Submission stays parked awaiting the authorized DUR-017 resolution path;
9720
- // the settlement obligation stays visible, nothing replays.
9721
- return "unknown";
9851
+ // Older Attempts may already have marked a native update unknown. Its exact
9852
+ // canonical acceptance is a factual resolution, never permission to retry an
9853
+ // external operation. The ledger wakes only when every unknown call is covered;
9854
+ // the next owner appends closure under the original call identity.
9855
+ const declared = yield* declaredCallsFor(
9856
+ records,
9857
+ runId,
9858
+ new Set(evidence.openToolCalls.map((call) => call.toolCallId)),
9859
+ );
9860
+
9861
+ let repaired = false;
9862
+
9863
+ for (const call of declared.values()) {
9864
+ if (
9865
+ snapshot.unknownResolutions.some((intent) => intent.toolCallId === call.toolCallId) ||
9866
+ !nativeUpdateAccepted(submission, call, records)
9867
+ )
9868
+ continue;
9869
+ yield* ledger
9870
+ .recordUnknownResolution(
9871
+ UnknownResolutionCommand.make({
9872
+ submissionId: submission.submissionId,
9873
+ toolCallId: call.toolCallId,
9874
+ author: RECONCILER_AUTHOR,
9875
+ reason: "The exact native update was canonically accepted",
9876
+ resolution: {
9877
+ _tag: "CompletedWithResult",
9878
+ result: { emitted: true },
9879
+ isFailure: false,
9880
+ },
9881
+ }),
9882
+ )
9883
+ .pipe(
9884
+ Effect.catchTag("UnknownResolutionConflict", (cause) =>
9885
+ LedgerError.make({
9886
+ operation: "recover native update",
9887
+ message: "Native acceptance conflicts with a retained resolution",
9888
+ cause,
9889
+ }),
9890
+ ),
9891
+ );
9892
+ repaired = true;
9893
+ }
9894
+ if (repaired) yield* wake.notify(submission.threadId);
9895
+
9896
+ return repaired ? "repaired" : "unknown";
9722
9897
  }
9723
9898
  case "AwaitApprovalDecision": {
9724
9899
  return yield* awaitApprovalForRecovery(snapshot, evidence, decision);
@@ -10372,8 +10547,11 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
10372
10547
 
10373
10548
  const factual = intent?.resolution;
10374
10549
 
10550
+ const acceptedNative =
10551
+ factual === undefined && (yield* updateRuntime.accepted(submission, selected.declared));
10552
+
10375
10553
  const reconciliation =
10376
- factual === undefined && selected.declared.executionKind === "ordinary"
10554
+ factual === undefined && !acceptedNative && selected.declared.executionKind === "ordinary"
10377
10555
  ? yield* reconciler
10378
10556
  .reconcile(
10379
10557
  DeclaredToolCallEvidence.make({
@@ -10391,9 +10569,11 @@ const make = Effect.fnUntraced(function* (bindings: ReadonlyArray<ResolvedBindin
10391
10569
  const completed =
10392
10570
  factual?._tag === "CompletedWithResult"
10393
10571
  ? factual
10394
- : Option.isSome(reconciliation) && reconciliation.value._tag === "CompletedWithResult"
10395
- ? reconciliation.value
10396
- : undefined;
10572
+ : acceptedNative
10573
+ ? { result: { emitted: true }, isFailure: false }
10574
+ : Option.isSome(reconciliation) && reconciliation.value._tag === "CompletedWithResult"
10575
+ ? reconciliation.value
10576
+ : undefined;
10397
10577
 
10398
10578
  const neverStarted =
10399
10579
  factual?._tag === "NeverHappened" ||
@@ -52,7 +52,7 @@ import {
52
52
  subagentRequestedRecordId,
53
53
  subagentStartedRecordId,
54
54
  } from "./RunJournal.ts";
55
- import type { RunStorageSession, RunWriter } from "./RunStorage.ts";
55
+ import type { RunStorageSession } from "./RunStorage.ts";
56
56
  import {
57
57
  submissionAbortRecordId,
58
58
  submissionInputRecordId,
@@ -74,7 +74,7 @@ export { RunContinuation, RunContextRecorded, EvidenceReference } from "./Record
74
74
  /** Writer and progress sequencer selected at the local owner's resource boundary. */
75
75
  export class CurrentRunWriter extends Context.Service<
76
76
  CurrentRunWriter,
77
- Pick<RunWriter, "threadId" | "tail" | "append" | "withProgress">
77
+ Pick<RunStorageSession, "threadId" | "tail" | "append" | "appendInput" | "withProgress">
78
78
  >()("@effect-agent/thread/CurrentRunWriter") {}
79
79
 
80
80
  /** Settlement publication keeps its original atomic authority and claim-scoped implementation. */
@@ -1736,12 +1736,12 @@ const modelResponseRecord = Effect.fnUntraced(function* (
1736
1736
  }
1737
1737
 
1738
1738
  const encodedMessages = yield* encodePrompt(Prompt.fromMessages([...promptMessages])).pipe(
1739
- Effect.mapError((cause) => journalError("Turn Prompt messages failed to encode", cause)),
1739
+ Effect.mapErrorEager((cause) => journalError("Turn Prompt messages failed to encode", cause)),
1740
1740
  );
1741
1741
 
1742
1742
  const messages = yield* decodePersistedJson(encodedMessages).pipe(
1743
- Effect.map(copyJson),
1744
- Effect.mapError((cause) =>
1743
+ Effect.mapEager(copyJson),
1744
+ Effect.mapErrorEager((cause) =>
1745
1745
  journalError("Turn Prompt messages exceed canonical persistence bounds", cause),
1746
1746
  ),
1747
1747
  );
@@ -1783,7 +1783,9 @@ const modelResponseRecord = Effect.fnUntraced(function* (
1783
1783
  }),
1784
1784
  }),
1785
1785
  }).pipe(
1786
- Effect.mapError((cause) => journalError("Invalid model response operation evidence", cause)),
1786
+ Effect.mapErrorEager((cause) =>
1787
+ journalError("Invalid model response operation evidence", cause),
1788
+ ),
1787
1789
  );
1788
1790
 
1789
1791
  if (payload.modelUsage !== undefined) {
@@ -1791,7 +1793,9 @@ const modelResponseRecord = Effect.fnUntraced(function* (
1791
1793
  return yield* journalError("Turn model usage must contain at least one completed call");
1792
1794
 
1793
1795
  const summary = yield* continuationUsage(payload.modelUsage).pipe(
1794
- Effect.mapError((cause) => journalError("Turn model usage exceeds accounting bounds", cause)),
1796
+ Effect.mapErrorEager((cause) =>
1797
+ journalError("Turn model usage exceeds accounting bounds", cause),
1798
+ ),
1795
1799
  );
1796
1800
 
1797
1801
  if (