@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
@@ -113,6 +113,8 @@ export interface RunWriter {
113
113
 
114
114
  export interface RunStorageSession extends RunWriter, RunOwnership {
115
115
  readonly claim: Claim;
116
+ /** Atomic original input/context plus the ledger marker, when the adapter supports it. */
117
+ readonly appendInput?: RunWriter["append"];
116
118
  /** Library-only initialization, before application/model IO. Hold progress before mutation
117
119
  * so the captured controls and this owner's acknowledged input remain one read view. */
118
120
  readonly withInitialization?: <A, E, R>(
@@ -176,69 +178,75 @@ const makeWriter = Effect.fnUntraced(function* (threadId: ThreadId) {
176
178
  }),
177
179
  );
178
180
 
179
- const append: RunWriter["append"] = Effect.fnUntraced(function* (batch, executions) {
180
- const captured = yield* PreparedAppend.capture(
181
- AppendRequest.make({
182
- threadId,
183
- expectedTailSequence: tail.sequence,
184
- batch,
185
- ...(executions === undefined ? {} : { executions }),
186
- }),
187
- ).pipe(
188
- Effect.mapError((cause) =>
189
- ThreadStoreError.make({
190
- operation: "capture append",
191
- message: cause.message,
192
- cause,
181
+ const makeAppend = Effect.gen(function* () {
182
+ const publisher = yield* ThreadStore;
183
+
184
+ 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 }),
193
191
  }),
194
- ),
195
- );
192
+ ).pipe(
193
+ Effect.mapError((cause) =>
194
+ ThreadStoreError.make({
195
+ operation: "capture append",
196
+ message: cause.message,
197
+ cause,
198
+ }),
199
+ ),
200
+ );
196
201
 
197
- return yield* owner.withProgress(
198
- threadId,
199
- owner.withMutation(
200
- Effect.gen(function* () {
201
- yield* checkActive;
202
- for (let retries = 0; ; retries++) {
203
- const result = yield* store
204
- .append(
205
- captured.expectedTailSequence === tail.sequence
206
- ? captured
207
- : AppendRequest.make({
208
- ...captured,
209
- expectedTailSequence: tail.sequence,
210
- }),
211
- )
212
- .pipe(
213
- Effect.catchTag("AppendConflict", (conflict) => {
214
- if (
215
- conflict.reason !== "tail" ||
216
- conflict.actualTailSequence === undefined ||
217
- retries >= 8
218
- )
219
- return Effect.fail(conflict);
220
- tail = { sequence: conflict.actualTailSequence };
221
- if (captured.executions !== undefined) return Effect.fail(conflict);
222
-
223
- return Effect.succeed(undefined);
224
- }),
225
- );
226
-
227
- if (result === undefined) continue;
228
- // A historical replay returns its original coordinates, not today's canonical tail.
229
- if (result.replayed) yield* refresh;
230
- else tail = { sequence: result.lastSequence };
231
-
232
- return result;
233
- }
234
- }).pipe(
235
- // Revoke uncertain writes before releasing the writer's mutation gate.
236
- Effect.onError((cause) =>
237
- isDefiniteWriteFailure(cause) ? Effect.void : ownership.release,
202
+ return yield* owner.withProgress(
203
+ threadId,
204
+ owner.withMutation(
205
+ Effect.gen(function* () {
206
+ yield* checkActive;
207
+ for (let retries = 0; ; retries++) {
208
+ const result = yield* publisher
209
+ .append(
210
+ captured.expectedTailSequence === tail.sequence
211
+ ? captured
212
+ : AppendRequest.make({
213
+ ...captured,
214
+ expectedTailSequence: tail.sequence,
215
+ }),
216
+ )
217
+ .pipe(
218
+ Effect.catchTag("AppendConflict", (conflict) => {
219
+ if (
220
+ conflict.reason !== "tail" ||
221
+ conflict.actualTailSequence === undefined ||
222
+ retries >= 8
223
+ )
224
+ return Effect.fail(conflict);
225
+ tail = { sequence: conflict.actualTailSequence };
226
+ if (captured.executions !== undefined) return Effect.fail(conflict);
227
+
228
+ return Effect.succeed(undefined);
229
+ }),
230
+ );
231
+
232
+ if (result === undefined) continue;
233
+ // A historical replay returns its original coordinates, not today's canonical tail.
234
+ if (result.replayed) yield* refresh;
235
+ else tail = { sequence: result.lastSequence };
236
+
237
+ return result;
238
+ }
239
+ }).pipe(
240
+ // Revoke uncertain writes before releasing the writer's mutation gate.
241
+ Effect.onError((cause) =>
242
+ isDefiniteWriteFailure(cause) ? Effect.void : ownership.release,
243
+ ),
238
244
  ),
239
245
  ),
240
- ),
241
- );
246
+ );
247
+ });
248
+
249
+ return append;
242
250
  });
243
251
 
244
252
  const writer = {
@@ -247,13 +255,14 @@ const makeWriter = Effect.fnUntraced(function* (threadId: ThreadId) {
247
255
  withProgress: <A, E, R>(effect: Effect.Effect<A, E, R>) =>
248
256
  owner.withProgress(threadId, Effect.andThen(checkActive, effect)),
249
257
  tail: Effect.sync(() => tail),
250
- append,
258
+ append: yield* makeAppend,
251
259
  checkActive: owner.withMutation(checkActive),
252
260
  refresh,
253
261
  };
254
262
 
255
263
  return {
256
264
  writer,
265
+ makeAppend,
257
266
  adoptTail: (sequence: CanonicalSequence) => {
258
267
  tail = { sequence };
259
268
  },
@@ -310,7 +319,7 @@ export const make = Effect.gen(function* () {
310
319
  });
311
320
  yield* store.materialize(ThreadMaterialization.make({ threadId: request.threadId }));
312
321
 
313
- const { writer, adoptTail } = yield* makeWriter(request.threadId).pipe(
322
+ const { writer, makeAppend, adoptTail } = yield* makeWriter(request.threadId).pipe(
314
323
  Effect.provideService(WriterOwnership, generation),
315
324
  Effect.provideService(ThreadStore, store),
316
325
  Effect.provideService(StorageOwner, owner),
@@ -318,9 +327,22 @@ export const make = Effect.gen(function* () {
318
327
 
319
328
  const owned = <A, E>(effect: Effect.Effect<A, E>) => generation.use(effect);
320
329
 
330
+ const inputPublisher = ledger.appendInput;
331
+
332
+ const appendInput =
333
+ inputPublisher === undefined
334
+ ? undefined
335
+ : yield* makeAppend.pipe(
336
+ Effect.provideService(ThreadStore, {
337
+ ...store,
338
+ append: (request) => inputPublisher(claimed.submissionId, request),
339
+ }),
340
+ );
341
+
321
342
  const session: RunStorageSession = {
322
343
  ...writer,
323
344
  claim: claimed,
345
+ ...(appendInput === undefined ? {} : { appendInput }),
324
346
  withInitialization: (effect) =>
325
347
  owner.withProgress(request.threadId, generation.use(effect)),
326
348
  release: generation.release,
@@ -36,6 +36,7 @@ import {
36
36
  ToolCallUnknown,
37
37
  WorkerAdmission,
38
38
  } from "./Records.ts";
39
+ import type { AppendRequest, AppendResult, ThreadStoreFailure } from "./ThreadStore.ts";
39
40
 
40
41
  export { IdempotencyKey, JoinedToHost, QueueSequence, Principal } from "../core/Receipt.ts";
41
42
 
@@ -1113,6 +1114,13 @@ export class SubmissionLedger extends Context.Service<
1113
1114
  readonly selectHead: (
1114
1115
  request: ClaimRequest,
1115
1116
  ) => Effect.Effect<Option.Option<Claim>, LedgerError>;
1117
+ /** Atomically publish a captured original input, active context and applied marker.
1118
+ * Optional adapters retain the ordinary append-then-repair protocol. The captured input
1119
+ * must be this owner's deterministic admission; a moved context boundary is refused. */
1120
+ readonly appendInput?: (
1121
+ submissionId: SubmissionId,
1122
+ request: AppendRequest,
1123
+ ) => Effect.Effect<AppendResult, ThreadStoreFailure>;
1116
1124
  readonly markInputApplied: (
1117
1125
  request: MarkInputAppliedRequest,
1118
1126
  ) => Effect.Effect<void, OwnershipLost | LedgerError>;
@@ -343,19 +343,20 @@ export class AppendRequest extends Schema.Class<AppendRequest>(
343
343
  expectedTailSequence: CanonicalSequence,
344
344
  }) {}
345
345
 
346
+ const RecordCount = Schema.Array(Schema.Unknown).check(Schema.isMaxLength(256));
347
+ const ExecutionRecordCount = Schema.Array(Schema.Unknown).check(Schema.isMaxLength(8));
348
+
346
349
  const AppendHeader = Schema.Struct({
347
350
  threadId: ThreadId,
348
351
  expectedTailSequence: CanonicalSequence,
349
352
  batchId: BatchId,
350
353
  producerId: ProducerId,
354
+ records: RecordCount,
355
+ executions: RecordCount,
351
356
  });
352
357
 
353
358
  const validateHeader = Schema.decodeUnknownSync(AppendHeader);
354
359
 
355
- const validateRecordCount = Schema.decodeUnknownSync(
356
- Schema.Array(Schema.Unknown).check(Schema.isMaxLength(256)),
357
- );
358
-
359
360
  const validateExecutionHeader = Schema.decodeUnknownSync(
360
361
  Schema.Struct({
361
362
  previousRevision: ExecutionUpdate.fields.previousRevision,
@@ -366,24 +367,36 @@ const validateExecutionHeader = Schema.decodeUnknownSync(
366
367
  originalSequence: ExecutionCheckpoint.fields.originalSequence,
367
368
  throughSequence: ExecutionCheckpoint.fields.throughSequence,
368
369
  batchId: ExecutionCheckpoint.fields.batchId,
370
+ operational: ExecutionRecordCount,
369
371
  }),
372
+ facts: ExecutionRecordCount,
370
373
  }),
371
374
  );
372
375
 
373
- const validateExecutionRecordCount = Schema.decodeUnknownSync(
374
- Schema.Array(Schema.Unknown).check(Schema.isMaxLength(8)),
375
- );
376
-
377
376
  /** Capture records once; wrapper fields retain their owning Schema's constraints. */
378
377
  const captureExecution = (input: ExecutionUpdate) => {
379
- const header = validateExecutionHeader(input);
380
- const operationalInput = input.checkpoint.operational;
378
+ const checkpointInput = input.checkpoint;
379
+ const operationalInput = checkpointInput.operational;
381
380
  const factsInput = input.facts;
382
381
 
383
- const operationalLength = validateExecutionRecordCount(operationalInput).length;
384
- const factsLength = validateExecutionRecordCount(factsInput).length;
382
+ const header = validateExecutionHeader({
383
+ previousRevision: input.previousRevision,
384
+ retire: input.retire,
385
+ checkpoint: {
386
+ version: checkpointInput.version,
387
+ canonicalRecords: checkpointInput.canonicalRecords,
388
+ originalSequence: checkpointInput.originalSequence,
389
+ throughSequence: checkpointInput.throughSequence,
390
+ batchId: checkpointInput.batchId,
391
+ operational: operationalInput,
392
+ },
393
+ facts: factsInput,
394
+ });
395
+
396
+ const operationalLength = header.checkpoint.operational.length;
397
+ const factsLength = header.facts.length;
385
398
 
386
- const progress = captureRecord(input.checkpoint.progressRecord);
399
+ const progress = captureRecord(checkpointInput.progressRecord);
387
400
 
388
401
  if (Result.isFailure(progress)) return Result.fail(progress.failure);
389
402
  const progressRecord = progress.success.canonical;
@@ -530,15 +543,19 @@ export const PreparedAppend = {
530
543
  return Effect.try({
531
544
  try: () =>
532
545
  Result.gen(function* () {
546
+ const executions = input.executions ?? [];
547
+ const recordInputs = input.batch.records;
548
+
533
549
  const header = validateHeader({
534
550
  ...input,
535
551
  batchId: input.batch.batchId,
536
552
  producerId: input.batch.producerId,
553
+ records: recordInputs,
554
+ executions,
537
555
  });
538
556
 
539
- validateRecordCount(input.batch.records);
540
- const executions = input.executions ?? [];
541
- const executionLength = validateRecordCount(executions).length;
557
+ const recordLength = header.records.length;
558
+ const executionLength = header.executions.length;
542
559
 
543
560
  const executionWrites: Array<PreparedAppend["executionWrites"][number]> = [];
544
561
 
@@ -546,7 +563,7 @@ export const PreparedAppend = {
546
563
  executionWrites.push(yield* captureExecution(executions[index]!));
547
564
  Object.freeze(executionWrites);
548
565
 
549
- if (input.batch.records.length === 0 && executionWrites.length === 0)
566
+ if (recordLength === 0 && executionWrites.length === 0)
550
567
  return yield* Result.fail(
551
568
  ThreadStoreError.make({
552
569
  operation: "prepare durable commit",
@@ -560,8 +577,11 @@ export const PreparedAppend = {
560
577
  message: "Active state exceeds its bounded transfer representation",
561
578
  }),
562
579
  );
563
- // Visit sparse slots too: capture owns each record's validation boundary.
564
- const encodings = yield* Result.all(Array.from(input.batch.records, captureRecord));
580
+ // Visit Schema-validated indexed slots, including sparse ones, never a caller's iterator.
581
+ const encodings = [];
582
+
583
+ for (let index = 0; index < recordLength; index++)
584
+ encodings.push(yield* captureRecord(recordInputs[index]!));
565
585
  const prefix = `{"batchId":${JSON.stringify(header.batchId)},"producerId":${JSON.stringify(header.producerId)},"records":[`;
566
586
  const batchJson = `${prefix}${encodings.map(({ json }) => json).join(",")}]}`;
567
587
 
@@ -2,6 +2,7 @@ import { Clock, Crypto, DateTime, Effect, Option, Schema, Stream } from "effect"
2
2
 
3
3
  import { Update, UpdateError } from "../../core/AgentUpdates.ts";
4
4
  import type { RunId, SubmissionId, ThreadId } from "../../core/Identifiers.ts";
5
+ import { nativeUpdateId } from "../../core/internal/agent-updates.ts";
5
6
  import { utf8ByteLength } from "../../core/internal/utf8.ts";
6
7
  import { IdempotencyKey } from "../../core/Receipt.ts";
7
8
  import { digestJson } from "../Digest.ts";
@@ -16,6 +17,8 @@ import {
16
17
  BatchId,
17
18
  CanonicalBatch,
18
19
  DefinitionDigests,
20
+ type CanonicalRecordEnvelope,
21
+ type DeclaredToolCall,
19
22
  type DeploymentId,
20
23
  PersistedJson,
21
24
  type ProducerId,
@@ -26,7 +29,7 @@ import { CurrentRunWriter, readRunEvidenceSnapshot } from "../RunContinuation.ts
26
29
  import { runIdForSubmission } from "../RunJournal.ts";
27
30
  import { LedgerError, type SubmissionSnapshot } from "../SubmissionLedger.ts";
28
31
  import { PreparedInput } from "../Subscription.ts";
29
- import { ThreadReader, ThreadStore, ThreadTailRequest } from "../ThreadStore.ts";
32
+ import { getRecord, ThreadReader, ThreadStore, ThreadTailRequest } from "../ThreadStore.ts";
30
33
  import {
31
34
  deliveryPredecessor,
32
35
  decodeWorkCursor,
@@ -44,6 +47,37 @@ const storage = () =>
44
47
 
45
48
  const rejected = (reason: UpdateError["reason"]) => UpdateError.make({ reason });
46
49
 
50
+ const updateDigest = (threadId: ThreadId, runId: RunId, updateId: string) =>
51
+ digestJson([threadId, runId, updateId]);
52
+
53
+ const nativeParameters = Schema.Struct({ value: Schema.Json });
54
+ const isNativeParameters = Schema.is(nativeParameters);
55
+ const definitionDigestsEqual = Schema.toEquivalence(DefinitionDigests);
56
+ const updateValuesEqual = Schema.toEquivalence(Schema.Json);
57
+
58
+ /** Canonical native acceptance proves only this exact update call, never an external effect.
59
+ * Its frozen delivery remains independently recoverable even when its Tool acknowledgement is lost.
60
+ */
61
+ export const nativeUpdateAccepted = (
62
+ submission: SubmissionSnapshot,
63
+ call: DeclaredToolCall,
64
+ records: ReadonlyArray<CanonicalRecordEnvelope>,
65
+ ): boolean => {
66
+ if (call.toolName !== "emit_update" || !isNativeParameters(call.parameters)) return false;
67
+ const value = call.parameters.value;
68
+
69
+ return records.some(
70
+ ({ record: { payload } }) =>
71
+ payload._tag === "AgentUpdateEmitted" &&
72
+ payload.update.threadId === submission.threadId &&
73
+ payload.update.agentId === submission.agentId &&
74
+ payload.update.runId === call.runId &&
75
+ payload.update.updateId === nativeUpdateId(call.runId, call.toolCallId) &&
76
+ definitionDigestsEqual(payload.definitions, submission.agentDigests) &&
77
+ updateValuesEqual(payload.update.value, value),
78
+ );
79
+ };
80
+
47
81
  /** Acceptance is fenced by the actual emitting Attempt; recovery only recreates frozen outbox rows. */
48
82
  export const makeAgentUpdateRuntime = Effect.fnUntraced(function* (options: {
49
83
  readonly deploymentId: DeploymentId;
@@ -58,6 +92,28 @@ export const makeAgentUpdateRuntime = Effect.fnUntraced(function* (options: {
58
92
 
59
93
  const reader = ThreadReader.fromStore(store);
60
94
 
95
+ // Terminal operation evidence excludes updates; fetch the original acceptance by its
96
+ // stable identity instead of expanding every operation's recovery history.
97
+ const accepted = Effect.fnUntraced(function* (
98
+ submission: SubmissionSnapshot,
99
+ call: DeclaredToolCall,
100
+ ) {
101
+ if (call.toolName !== "emit_update") return false;
102
+
103
+ const digest = yield* updateDigest(
104
+ submission.threadId,
105
+ call.runId,
106
+ nativeUpdateId(call.runId, call.toolCallId),
107
+ ).pipe(Effect.provideService(Crypto.Crypto, crypto), Effect.mapError(storage));
108
+
109
+ const record = yield* getRecord({
110
+ threadId: submission.threadId,
111
+ recordId: RecordId.make(`agent-update:${digest}`),
112
+ }).pipe(Effect.provideService(ThreadReader, reader), Effect.mapError(storage));
113
+
114
+ return Option.isSome(record) && nativeUpdateAccepted(submission, call, [record.value]);
115
+ });
116
+
61
117
  const readRun = Effect.fnUntraced(function* (threadId: ThreadId, submissionId: SubmissionId) {
62
118
  const tail = yield* store
63
119
  .inspectTail(ThreadTailRequest.make({ threadId }))
@@ -194,7 +250,7 @@ export const makeAgentUpdateRuntime = Effect.fnUntraced(function* (options: {
194
250
  Effect.mapError(() => rejected("validation")),
195
251
  );
196
252
 
197
- const digest = yield* digestJson([request.submission.threadId, request.runId, updateId]).pipe(
253
+ const digest = yield* updateDigest(request.submission.threadId, request.runId, updateId).pipe(
198
254
  Effect.provideService(Crypto.Crypto, crypto),
199
255
  Effect.mapError(storage),
200
256
  );
@@ -367,5 +423,5 @@ export const makeAgentUpdateRuntime = Effect.fnUntraced(function* (options: {
367
423
  ),
368
424
  );
369
425
 
370
- return { emit, repair: insert, repairRun };
426
+ return { emit, accepted, repair: insert, repairRun };
371
427
  });
@@ -1,17 +1,32 @@
1
1
  import { Effect, Option, Schema, Stream } from "effect";
2
2
  import { Prompt } from "effect/ai";
3
3
 
4
- import { CanonicalSequence, type CanonicalRecordEnvelope } from "../Records.ts";
4
+ import {
5
+ CanonicalSequence,
6
+ type CanonicalRecordEnvelope,
7
+ type RecordEnvelope,
8
+ type UserInputRecorded,
9
+ } from "../Records.ts";
5
10
  import { RunJournalError, toolCallSettledRecordId } from "../RunJournal.ts";
6
11
  import { submissionSettlementRecordId } from "../SubmissionLedger.ts";
7
12
  import { getRecord, getRunInput, PROMPT_EVIDENCE_TAGS, ThreadReader } from "../ThreadStore.ts";
8
13
  import type { JournalRecordEnvelope } from "./journal-metadata.ts";
9
14
 
15
+ /** A captured original input can prepare context before its atomic publication. It carries
16
+ * an expected position, never a committed observation cursor or dispatch authority. */
17
+ export type InitialContextInput =
18
+ | CanonicalRecordEnvelope
19
+ | {
20
+ readonly threadId: CanonicalRecordEnvelope["threadId"];
21
+ readonly sequence: CanonicalRecordEnvelope["sequence"];
22
+ readonly record: RecordEnvelope & { readonly payload: UserInputRecorded };
23
+ };
24
+
10
25
  const invalid = (message: string) => RunJournalError.make({ message });
11
26
  const promptTag = new Set<string>(PROMPT_EVIDENCE_TAGS);
12
27
 
13
28
  /** Fresh admission trusts validated immutable history; recovery verifies its saved Prompt digest. */
14
- export const initialContext = Effect.fnUntraced(function* (original: CanonicalRecordEnvelope) {
29
+ export const initialContext = Effect.fnUntraced(function* (original: InitialContextInput) {
15
30
  const reader = yield* ThreadReader;
16
31
  const threadId = original.threadId;
17
32
  const through = CanonicalSequence.make(original.sequence - 1);
@@ -6,9 +6,9 @@ import { boundedValueFootprint } from "../../engine/internal/bounded-value.ts";
6
6
  import { canonicalJson, digestCanonicalJson, utf8ByteLength } from "../Digest.ts";
7
7
  import {
8
8
  CanonicalSequence,
9
+ type CanonicalRecordEnvelope,
9
10
  CURRENT_RECORD_FORMAT,
10
11
  PromptRecord,
11
- type CanonicalRecordEnvelope,
12
12
  type Digest,
13
13
  type PromptRecordEnvelope,
14
14
  type RecordEnvelope,
@@ -23,6 +23,7 @@ import {
23
23
  ThreadStore,
24
24
  ThreadTailRequest,
25
25
  } from "../ThreadStore.ts";
26
+ import type { InitialContextInput } from "./initial-context.ts";
26
27
  import type { JournalRecordEnvelope } from "./journal-metadata.ts";
27
28
  import { promptJsonFootprint } from "./prompt-footprint.ts";
28
29
  import { captureRecord } from "./record-encoding.ts";
@@ -149,12 +150,14 @@ const retainedBytes = (value: unknown, json: string, allowance: number) => {
149
150
  return footprint === undefined ? undefined : encodedBytes + 2 * footprint;
150
151
  };
151
152
 
152
- const encodeHistory = Effect.fnUntraced(function* (prompt: Prompt.Prompt, allowance: number) {
153
- const value = yield* encodePrompt(prompt);
154
- const encoded = canonicalJson(value);
153
+ const encodeHistory = (prompt: Prompt.Prompt, allowance: number) =>
154
+ Effect.suspend(() =>
155
+ Effect.mapEager(encodePrompt(prompt), (value) => {
156
+ const encoded = canonicalJson(value);
155
157
 
156
- return { encoded, bytes: retainedBytes(value, encoded, allowance) };
157
- });
158
+ return { encoded, bytes: retainedBytes(value, encoded, allowance) };
159
+ }),
160
+ );
158
161
 
159
162
  // Finish parsing/decoding before suspending for suffix reads. Only the native prefix and its
160
163
  // canonical string leave this Effect; it does not keep a second parsed root in the outer Run.
@@ -252,7 +255,9 @@ const suffixRecordFootprint = (entry: PromptRecordEnvelope, allowance: number) =
252
255
  * acknowledged, consecutive appends. Never authority for writes or recovery; any uncertainty
253
256
  * discards this derivative and completion rereads canonical history.
254
257
  */
255
- export const makeCommittedPromptSuffix = (original: CanonicalRecordEnvelope) => {
258
+ export const makeCommittedPromptSuffix = (
259
+ original: Pick<CanonicalRecordEnvelope, "threadId" | "sequence" | "record">,
260
+ ) => {
256
261
  const records: Array<PromptRecordEnvelope> = [];
257
262
 
258
263
  const runId =
@@ -558,7 +563,7 @@ export const makePromptHistoryCache = Effect.fnUntraced(function* () {
558
563
  const complete = Effect.fnUntraced(
559
564
  function* (
560
565
  writer: WriterIdentity,
561
- original: CanonicalRecordEnvelope,
566
+ original: InitialContextInput,
562
567
  history: PromptHistory,
563
568
  committed?: CommittedPromptSuffix,
564
569
  ) {
@@ -3083,7 +3083,9 @@ export const makeWorkerRuntime = Effect.fnUntraced(function* (options: WorkerRun
3083
3083
  ? "stopped"
3084
3084
  : "stopping"
3085
3085
  : control.active !== null
3086
- ? "active"
3086
+ ? control.active.state === "unknown"
3087
+ ? "unknown"
3088
+ : "active"
3087
3089
  : delivery !== undefined
3088
3090
  ? "starting"
3089
3091
  : "idle"),
@@ -1,40 +1,14 @@
1
1
  import type { Effect, Option } from "effect";
2
- import type { Tool } from "effect/ai";
3
2
  import * as Context from "effect/Context";
4
3
  import * as Schema from "effect/Schema";
5
4
 
6
5
  import { ToolCallId } from "../core/Identifiers.ts";
7
6
 
8
- /**
9
- * Declared external execution class of one Tool, used by the durable runtime
10
- * to decide which Tool Calls need the prepared/settled uncertainty protocol:
11
- *
12
- * - `"readonly"`: the handler performs no external mutation. A crash between
13
- * start and settlement is a free re-run; no prepared record is written.
14
- * - `"idempotent"`: the handler declares an external idempotency contract
15
- * (it owns key derivation). Prepared/settled records are written and
16
- * recovery may re-execute without reconciliation proof.
17
- * - `"uncertain"`: no external contract is declared. Prepared/settled records
18
- * are written and recovery must reconcile or record an Unknown Outcome.
19
- */
20
- export type ToolExecutionClassValue = "readonly" | "idempotent" | "uncertain";
21
-
22
- /**
23
- * Effect AI Tool annotation key declaring a Tool's execution class, applied
24
- * with `Tool.annotate(ToolExecutionClass, "...")`.
25
- *
26
- * Unannotated Tools default to `"uncertain"`: security and durability
27
- * decisions are fail-closed, so the framework never infers a safer class
28
- * from a Tool's shape.
29
- */
30
- export const ToolExecutionClass = Context.Reference<ToolExecutionClassValue>(
31
- "@effect-agent/engine/ToolExecutionClass",
32
- { defaultValue: () => "uncertain" },
33
- );
34
-
35
- /** Read a Tool's declared execution class, falling back to the fail-closed `"uncertain"` default. */
36
- export const getToolExecutionClass = (tool: Tool.Any): ToolExecutionClassValue =>
37
- Context.get(tool.annotations, ToolExecutionClass);
7
+ export {
8
+ ToolExecutionClass,
9
+ getToolExecutionClass,
10
+ type ToolExecutionClassValue,
11
+ } from "../core/internal/tool-execution.ts";
38
12
 
39
13
  /** Stable identity of one Step within one Tool Call: `(toolCallId, stepName)`. */
40
14
  export interface RunStepKey {
@@ -71,6 +71,7 @@ import {
71
71
  type TurnId,
72
72
  } from "../../core/Identifiers.ts";
73
73
  import { IdGenerator } from "../../core/IdGenerator.ts";
74
+ import { nativeUpdateId } from "../../core/internal/agent-updates.ts";
74
75
  import { copyJson } from "../../core/internal/json.ts";
75
76
  import { utf8ByteLength } from "../../core/internal/utf8.ts";
76
77
  import { IdempotencyKey } from "../../core/Receipt.ts";
@@ -9126,7 +9127,7 @@ function executeWithCompletion<
9126
9127
  );
9127
9128
 
9128
9129
  const updateId = yield* Schema.decodeEffect(IdempotencyKey)(
9129
- `tool:${context.runId}:${call.toolCallId}`,
9130
+ nativeUpdateId(context.runId, call.toolCallId),
9130
9131
  ).pipe(Effect.mapError(() => UpdateError.make({ reason: "validation" })));
9131
9132
 
9132
9133
  const emitter = yield* Emitter;