effect-agent 0.1.0-beta.103 → 0.1.0-beta.106

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 (166) hide show
  1. package/dist/{Agent-CM6JubNX.d.mts → Agent-Bk-mLtov.d.mts} +2 -2
  2. package/dist/{AgentError-CggcAQ7V.d.mts → AgentError-Bn1ytXRD.d.mts} +20 -4
  3. package/dist/{AgentRuntime-B1SXMVN7.d.mts → AgentRuntime-BEXToYl1.d.mts} +8 -8
  4. package/dist/{AgentRuntime-BWOnNc0d.mjs → AgentRuntime-e2M5UoXn.mjs} +4 -3
  5. package/dist/AgentRuntime-e2M5UoXn.mjs.map +1 -0
  6. package/dist/{DurableAgentRuntime-C9eRZS9N.mjs → DurableAgentRuntime-wd1x0TcB.mjs} +67 -36
  7. package/dist/DurableAgentRuntime-wd1x0TcB.mjs.map +1 -0
  8. package/dist/{EventSource-K7XUzurY.d.mts → EventSource-pH-v0k42.d.mts} +3 -3
  9. package/dist/FailureDiagnostic-BElLOoED.mjs +274 -0
  10. package/dist/FailureDiagnostic-BElLOoED.mjs.map +1 -0
  11. package/dist/FailureDiagnostic-CaAkzGHL.d.mts +223 -0
  12. package/dist/{Messaging-QMYhp297.d.mts → Messaging-Bl4SBKpR.d.mts} +3 -3
  13. package/dist/{MessagingHost-gAxs5gme.d.mts → MessagingHost-nwBMdRoh.d.mts} +3 -3
  14. package/dist/{Output-CjocJzsl.d.mts → Output-B6RQ5jRU.d.mts} +2 -2
  15. package/dist/{PreparedInputAdmission-KLk5rGFI.d.mts → PreparedInputAdmission-D3-BgmA9.d.mts} +8 -4
  16. package/dist/{Records-Bidb7ByL.d.mts → Records-B4S02MX1.d.mts} +201 -14
  17. package/dist/{RunJournal-srpbEBEy.mjs → RunJournal-BdIlgAEj.mjs} +2 -2
  18. package/dist/{RunJournal-srpbEBEy.mjs.map → RunJournal-BdIlgAEj.mjs.map} +1 -1
  19. package/dist/{RunOptions-Bruk54SE.d.mts → RunOptions-qOcPv08p.d.mts} +10 -5
  20. package/dist/{Schedule-Cy9up8Uf.d.mts → Schedule-D2TVEu3W.d.mts} +7 -2
  21. package/dist/{Scheduling-CHCsSCGo.mjs → Scheduling-DPb2QyAK.mjs} +2 -2
  22. package/dist/{Scheduling-CHCsSCGo.mjs.map → Scheduling-DPb2QyAK.mjs.map} +1 -1
  23. package/dist/{Subagent-DP0CzO16.d.mts → Subagent-BxuDuCHt.d.mts} +172 -8
  24. package/dist/{Subagent-C2s8PFrd.mjs → Subagent-uXWHXiKb.mjs} +64 -29
  25. package/dist/Subagent-uXWHXiKb.mjs.map +1 -0
  26. package/dist/{SubagentHost-CYcxkpRc.d.mts → SubagentHost-DEPw4YME.d.mts} +6 -3
  27. package/dist/{Subscription-CHyoQelH.d.mts → Subscription-nX0rz4GQ.d.mts} +3 -3
  28. package/dist/{SubscriptionInput-DqrHW-Ja.d.mts → SubscriptionInput-CAG3_pyJ.d.mts} +3 -3
  29. package/dist/{Worker--j87JI__.d.mts → Worker-Bbj9uq5H.d.mts} +5 -2
  30. package/dist/{agent-registration-ByeHejH3.mjs → agent-registration-B5CI-Ygk.mjs} +7 -5
  31. package/dist/agent-registration-B5CI-Ygk.mjs.map +1 -0
  32. package/dist/capabilities/Commands.d.mts +1 -1
  33. package/dist/capabilities/Messaging.d.mts +2 -2
  34. package/dist/capabilities/RunHooks.d.mts +1 -1
  35. package/dist/capabilities/Subagent.d.mts +2 -2
  36. package/dist/capabilities/Subagent.mjs +1 -1
  37. package/dist/core/Agent.d.mts +1 -1
  38. package/dist/core/AgentError.d.mts +2 -2
  39. package/dist/core/AgentError.mjs +19 -2
  40. package/dist/core/AgentError.mjs.map +1 -1
  41. package/dist/core/FailureDiagnostic.d.mts +2 -0
  42. package/dist/core/FailureDiagnostic.mjs +2 -0
  43. package/dist/core/Worker.d.mts +1 -1
  44. package/dist/core/Worker.mjs +4 -1
  45. package/dist/core/Worker.mjs.map +1 -1
  46. package/dist/durable/ActivityStore.d.mts +1 -1
  47. package/dist/durable/ActivityStore.mjs +1 -1
  48. package/dist/durable/Admin.d.mts +1 -1
  49. package/dist/durable/Admin.mjs +1 -1
  50. package/dist/durable/AgentRegistration.d.mts +1 -1
  51. package/dist/durable/AgentRegistration.mjs +1 -1
  52. package/dist/durable/Certification.d.mts +1 -1
  53. package/dist/durable/CommittedActivity.d.mts +1 -1
  54. package/dist/durable/CommittedActivity.mjs +1 -1
  55. package/dist/durable/Digest.d.mts +1 -1
  56. package/dist/durable/Digest.mjs +7 -7
  57. package/dist/durable/Digest.mjs.map +1 -1
  58. package/dist/durable/DurableAgentRuntime.d.mts +1 -1
  59. package/dist/durable/DurableAgentRuntime.mjs +1 -1
  60. package/dist/durable/EventSource.d.mts +1 -1
  61. package/dist/durable/EventSource.mjs +1 -1
  62. package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
  63. package/dist/durable/GitHubWorkflowSource.mjs +1 -1
  64. package/dist/durable/MessageDelivery.d.mts +15 -3
  65. package/dist/durable/MessageDelivery.mjs +44 -24
  66. package/dist/durable/MessageDelivery.mjs.map +1 -1
  67. package/dist/durable/MessageDeliveryStoreConformance.d.mts +4 -1
  68. package/dist/durable/MessageDeliveryStoreConformance.mjs +1 -1
  69. package/dist/durable/PersistentHistory.d.mts +1 -1
  70. package/dist/durable/PersistentHistory.mjs +2 -2
  71. package/dist/durable/PreparedInputAdmission.d.mts +1 -1
  72. package/dist/durable/PreparedInputAdmission.mjs +8 -4
  73. package/dist/durable/PreparedInputAdmission.mjs.map +1 -1
  74. package/dist/durable/Records.d.mts +1 -1
  75. package/dist/durable/Records.mjs +831 -2
  76. package/dist/durable/Records.mjs.map +1 -0
  77. package/dist/durable/Recovery.d.mts +1 -1
  78. package/dist/durable/Recovery.mjs +1 -1
  79. package/dist/durable/RunJournal.d.mts +1 -1
  80. package/dist/durable/RunJournal.mjs +1 -1
  81. package/dist/durable/Schedule.d.mts +1 -1
  82. package/dist/durable/Schedule.mjs +12 -3
  83. package/dist/durable/Schedule.mjs.map +1 -1
  84. package/dist/durable/ScheduleStoreConformance.d.mts +1 -1
  85. package/dist/durable/ScheduleStoreConformance.mjs +1 -1
  86. package/dist/durable/ScheduleTransition.d.mts +1 -1
  87. package/dist/durable/ScheduleTransition.mjs +1 -1
  88. package/dist/durable/Scheduling.d.mts +2 -2
  89. package/dist/durable/Scheduling.mjs +1 -1
  90. package/dist/durable/SqlMessageDeliveryStore.mjs +13 -11
  91. package/dist/durable/SqlMessageDeliveryStore.mjs.map +1 -1
  92. package/dist/durable/SqlStorageV2Upgrade.d.mts +2 -2
  93. package/dist/durable/SqlStorageV2Upgrade.mjs +1 -1
  94. package/dist/durable/SqlSubscriptionStore.d.mts +2 -2
  95. package/dist/durable/SqlSubscriptionStore.mjs +1 -1
  96. package/dist/durable/SqlThreadNativeReads.d.mts +1 -1
  97. package/dist/durable/SqlThreadNativeReads.mjs +2 -2
  98. package/dist/durable/SubmissionLedger.d.mts +1 -1
  99. package/dist/durable/SubmissionLedger.mjs +6 -3
  100. package/dist/durable/SubmissionLedger.mjs.map +1 -1
  101. package/dist/durable/SubmissionLedgerConformance.d.mts +1 -1
  102. package/dist/durable/SubmissionLedgerConformance.mjs +1 -1
  103. package/dist/durable/SubmissionStatus.d.mts +1 -1
  104. package/dist/durable/Subscription.d.mts +1 -1
  105. package/dist/durable/Subscription.mjs +1 -1
  106. package/dist/durable/SubscriptionInput.d.mts +1 -1
  107. package/dist/durable/SubscriptionInput.mjs +2 -2
  108. package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
  109. package/dist/durable/SubscriptionStoreConformance.mjs +1 -1
  110. package/dist/durable/SubscriptionTools.d.mts +3 -3
  111. package/dist/durable/SubscriptionTransition.d.mts +1 -1
  112. package/dist/durable/SubscriptionTransition.mjs +1 -1
  113. package/dist/durable/Subscriptions.d.mts +5 -5
  114. package/dist/durable/Subscriptions.mjs +1 -1
  115. package/dist/durable/ThreadContextHistory.d.mts +1 -1
  116. package/dist/durable/ThreadContextHistory.mjs +1 -1
  117. package/dist/durable/ThreadContextHistoryProjection.d.mts +1 -1
  118. package/dist/durable/ThreadContextHistoryProjection.mjs +1 -1
  119. package/dist/durable/ThreadInvariants.d.mts +1 -1
  120. package/dist/durable/ThreadInvariants.mjs +2 -2
  121. package/dist/durable/ThreadProjection.d.mts +1 -1
  122. package/dist/durable/ThreadProjection.mjs +1 -1
  123. package/dist/durable/ThreadProjectionMaintenance.d.mts +1 -1
  124. package/dist/durable/ThreadStore.d.mts +1 -1
  125. package/dist/durable/ThreadStore.mjs +2 -2
  126. package/dist/durable/ThreadStoreConformance.d.mts +1 -1
  127. package/dist/durable/ThreadStoreConformance.mjs +1 -1
  128. package/dist/durable/ToolReconciler.mjs +1 -1
  129. package/dist/durable/WorkerHost.d.mts +3 -3
  130. package/dist/engine/AgentRuntime.d.mts +1 -1
  131. package/dist/engine/AgentRuntime.mjs +1 -1
  132. package/dist/engine/MessagingHost.d.mts +1 -1
  133. package/dist/engine/Output.d.mts +1 -1
  134. package/dist/engine/RunOptions.d.mts +1 -1
  135. package/dist/engine/RunOptions.mjs +2 -0
  136. package/dist/engine/RunOptions.mjs.map +1 -1
  137. package/dist/engine/SubagentHost.d.mts +1 -1
  138. package/dist/engine/SubagentHost.mjs.map +1 -1
  139. package/dist/index.d.mts +18 -17
  140. package/dist/index.mjs +8 -7
  141. package/package.json +1 -1
  142. package/src/capabilities/internal/subagent-background.ts +66 -23
  143. package/src/capabilities/internal/subagent-contract.ts +4 -0
  144. package/src/core/AgentError.ts +20 -0
  145. package/src/core/FailureDiagnostic.ts +343 -0
  146. package/src/core/Worker.ts +4 -1
  147. package/src/durable/Digest.ts +22 -28
  148. package/src/durable/DurableAgentRuntime.ts +37 -13
  149. package/src/durable/MessageDelivery.ts +82 -24
  150. package/src/durable/PreparedInputAdmission.ts +17 -4
  151. package/src/durable/Records.ts +5 -15
  152. package/src/durable/Schedule.ts +11 -2
  153. package/src/durable/SqlMessageDeliveryStore.ts +21 -9
  154. package/src/durable/SubmissionLedger.ts +4 -1
  155. package/src/durable/internal/agent-registration.ts +46 -14
  156. package/src/durable/internal/worker-host.ts +32 -19
  157. package/src/engine/RunOptions.ts +11 -3
  158. package/src/engine/SubagentHost.ts +3 -0
  159. package/src/engine/internal/agent-runtime.ts +23 -16
  160. package/src/index.ts +1 -0
  161. package/dist/AgentRuntime-BWOnNc0d.mjs.map +0 -1
  162. package/dist/DurableAgentRuntime-C9eRZS9N.mjs.map +0 -1
  163. package/dist/Records-D8167fHn.mjs +0 -844
  164. package/dist/Records-D8167fHn.mjs.map +0 -1
  165. package/dist/Subagent-C2s8PFrd.mjs.map +0 -1
  166. package/dist/agent-registration-ByeHejH3.mjs.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { Clock, Context, Crypto, Effect, Layer, Result, Schema, Semaphore } from "effect";
2
2
 
3
+ import * as FailureDiagnostic from "../core/FailureDiagnostic.ts";
3
4
  import { ThreadId } from "../core/Identifiers.ts";
4
5
  import { Receipt } from "../core/Receipt.ts";
5
6
  import { WorkerUpdate } from "../core/Worker.ts";
@@ -86,6 +87,8 @@ export const MessageDeliveryRecord = Schema.Struct({
86
87
  parkReason: Schema.NullOr(ParkReason),
87
88
  leaseUntilMillis: Schema.NullOr(ScheduleInstant),
88
89
  retry: ScheduleRetry,
90
+ /** Last failed admission/status check, retained across retries and successful recovery. */
91
+ lastFailureDiagnostic: Schema.optionalKey(FailureDiagnostic.Diagnostic),
89
92
  }).check(
90
93
  Schema.makeFilter(
91
94
  (record) =>
@@ -117,6 +120,8 @@ export type MessageDeliveryRecord = typeof MessageDeliveryRecord.Type;
117
120
  export class MessageDeliveryError extends Schema.TaggedError<MessageDeliveryError>()(
118
121
  "MessageDeliveryError",
119
122
  {
123
+ cause: Schema.optionalKey(FailureDiagnostic.Value),
124
+ stack: Schema.optionalKey(Schema.String),
120
125
  reason: Schema.Literals([
121
126
  "validation",
122
127
  "conflict",
@@ -151,9 +156,24 @@ export const MessageDeliveryChange = Schema.Union([
151
156
  Schema.Struct({ _tag: Schema.Literal("Accept"), ...fence, receipt: Receipt }),
152
157
  Schema.Struct({ _tag: Schema.Literal("Process"), ...fence, settlement: Settlement }),
153
158
  Schema.Struct({ _tag: Schema.Literal("ObservePending"), ...fence }),
154
- Schema.Struct({ _tag: Schema.Literal("Refuse"), ...fence, code: BoundedName }),
155
- Schema.Struct({ _tag: Schema.Literal("Retry"), ...fence, reason: ScheduleRetryReason }),
156
- Schema.Struct({ _tag: Schema.Literal("Park"), ...fence, reason: ParkReason }),
159
+ Schema.Struct({
160
+ _tag: Schema.Literal("Refuse"),
161
+ ...fence,
162
+ code: BoundedName,
163
+ diagnostic: Schema.optionalKey(FailureDiagnostic.Diagnostic),
164
+ }),
165
+ Schema.Struct({
166
+ _tag: Schema.Literal("Retry"),
167
+ ...fence,
168
+ reason: ScheduleRetryReason,
169
+ diagnostic: Schema.optionalKey(FailureDiagnostic.Diagnostic),
170
+ }),
171
+ Schema.Struct({
172
+ _tag: Schema.Literal("Park"),
173
+ ...fence,
174
+ reason: ParkReason,
175
+ diagnostic: Schema.optionalKey(FailureDiagnostic.Diagnostic),
176
+ }),
157
177
  Schema.Struct({ _tag: Schema.Literal("Recover"), ...fence, deadlineAtMillis: ScheduleInstant }),
158
178
  /** Waiting for earlier admission never spends an automatic transport attempt. */
159
179
  Schema.Struct({ _tag: Schema.Literal("Defer"), ...fence, untilMillis: ScheduleInstant }),
@@ -292,8 +312,8 @@ export const sameMessageDeliveryIdentity = (
292
312
  left.createdAtMillis === right.createdAtMillis &&
293
313
  left.initialDeadlineAtMillis === right.initialDeadlineAtMillis;
294
314
 
295
- const error = (reason: MessageDeliveryError["reason"], operation: string) =>
296
- MessageDeliveryError.make({ reason, operation });
315
+ const error = (reason: MessageDeliveryError["reason"], operation: string, cause?: unknown) =>
316
+ MessageDeliveryError.make({ reason, operation, ...(cause === undefined ? {} : { cause }) });
297
317
 
298
318
  export const validateMessageDelivery = <A, I>(
299
319
  schema: Schema.Codec<A, I>,
@@ -328,23 +348,23 @@ export const prepareMessageDelivery = Effect.fn("MessageDelivery.prepare")(funct
328
348
  policy: options.policy ?? defaultMessageDeliveryPolicy,
329
349
  }).pipe(
330
350
  Effect.flatMap(Schema.decodeEffect(Schema.fromJsonString(MessageDeliveryPreparation))),
331
- Effect.mapError(() => error("validation", "prepare")),
351
+ Effect.mapError((cause) => error("validation", "prepare", cause)),
332
352
  );
333
353
 
334
354
  const envelope = snapshot.envelope;
335
355
 
336
356
  const encoded = yield* Schema.encodeEffect(PreparedInput)(envelope).pipe(
337
- Effect.mapError(() => error("validation", "prepare")),
357
+ Effect.mapError((cause) => error("validation", "prepare", cause)),
338
358
  );
339
359
 
340
360
  const inputDigest = yield* digestJson(encoded.input).pipe(
341
- Effect.mapError(() => error("storage", "digest")),
361
+ Effect.mapError((cause) => error("storage", "digest", cause)),
342
362
  );
343
363
 
344
364
  if (inputDigest !== envelope.inputDigest) return yield* error("corrupt", "input-digest");
345
365
 
346
366
  const envelopeDigest = yield* digestJson(encoded).pipe(
347
- Effect.mapError(() => error("storage", "digest")),
367
+ Effect.mapError((cause) => error("storage", "digest", cause)),
348
368
  );
349
369
 
350
370
  return yield* validateMessageDelivery(
@@ -390,7 +410,14 @@ export const applyMessageDeliveryChange = (
390
410
  if (record.version !== change.expectedVersion) return conflict();
391
411
  if (record.status === "processed" || record.status === "refused") return conflict();
392
412
  const now = change.nowMillis;
393
- const base = { ...record, version: record.version + 1 };
413
+
414
+ const base = {
415
+ ...record,
416
+ version: record.version + 1,
417
+ ...("diagnostic" in change && change.diagnostic !== undefined
418
+ ? { lastFailureDiagnostic: change.diagnostic }
419
+ : {}),
420
+ };
394
421
 
395
422
  const parked = (reason: typeof ParkReason.Type): MessageDeliveryRecord => ({
396
423
  ...base,
@@ -636,12 +663,12 @@ export class MessageDeliveryDriver extends Context.Service<
636
663
  if (claimed.status === "parked") return claimed;
637
664
 
638
665
  const envelope = yield* Schema.encodeEffect(PreparedInput)(claimed.envelope).pipe(
639
- Effect.mapError(() => error("corrupt", "envelope")),
666
+ Effect.mapError((cause) => error("corrupt", "envelope", cause)),
640
667
  );
641
668
 
642
669
  const digest = yield* digestJson(envelope).pipe(
643
670
  Effect.provideService(Crypto.Crypto, crypto),
644
- Effect.mapError(() => error("storage", "digest")),
671
+ Effect.mapError((cause) => error("storage", "digest", cause)),
645
672
  );
646
673
 
647
674
  if (digest !== claimed.envelopeDigest)
@@ -675,15 +702,23 @@ export class MessageDeliveryDriver extends Context.Service<
675
702
  const outcome = yield* admitPreparedInput(
676
703
  admission.submit(claimed.envelope),
677
704
  timeout,
678
- ).pipe(Effect.mapError(() => error("corrupt", "admission")));
705
+ ).pipe(Effect.mapError((cause) => error("corrupt", "admission", cause)));
679
706
 
680
707
  yield* failpoint.hit("message-delivery:admission:after");
681
708
  if (outcome._tag === "Receipt")
682
709
  return yield* commit({ _tag: "Accept", receipt: outcome.receipt });
683
710
  if (outcome._tag === "Refused")
684
- return yield* commit({ _tag: "Refuse", code: outcome.error.code });
711
+ return yield* commit({
712
+ _tag: "Refuse",
713
+ code: outcome.error.code,
714
+ diagnostic: FailureDiagnostic.capture(outcome.error),
715
+ });
685
716
 
686
- return yield* commit({ _tag: "Retry", reason: outcome.reason });
717
+ return yield* commit({
718
+ _tag: "Retry",
719
+ reason: outcome.reason,
720
+ diagnostic: outcome.diagnostic,
721
+ });
687
722
  }
688
723
  if (claimed.receipt === null) return yield* error("corrupt", "receipt");
689
724
  if (admission.submissionStatus === undefined)
@@ -693,28 +728,51 @@ export class MessageDeliveryDriver extends Context.Service<
693
728
  Effect.timeout(timeout),
694
729
  Effect.map((status) => ({ _tag: "Status" as const, status })),
695
730
  Effect.catchTag("ScheduledInputRetryable", (failure) =>
696
- Effect.succeed({ _tag: "Retry" as const, reason: failure.reason }),
731
+ Effect.succeed({
732
+ _tag: "Retry" as const,
733
+ reason: failure.reason,
734
+ diagnostic: FailureDiagnostic.capture(failure),
735
+ }),
697
736
  ),
698
- Effect.catchTag("ScheduledInputRefused", () =>
699
- Effect.succeed({ _tag: "Unavailable" as const }),
737
+ Effect.catchTag("ScheduledInputRefused", (failure) =>
738
+ Effect.succeed({
739
+ _tag: "Unavailable" as const,
740
+ diagnostic: FailureDiagnostic.capture(failure),
741
+ }),
700
742
  ),
701
- Effect.catchTag("TimeoutError", () =>
702
- Effect.succeed({ _tag: "Retry" as const, reason: "timeout" as const }),
743
+ Effect.catchTag("TimeoutError", (failure) =>
744
+ Effect.succeed({
745
+ _tag: "Retry" as const,
746
+ reason: "timeout" as const,
747
+ diagnostic: FailureDiagnostic.capture(failure),
748
+ }),
703
749
  ),
704
750
  Effect.catchTag("ScheduleStorageError", (failure) =>
705
751
  failure.reason === "unavailable"
706
- ? Effect.succeed({ _tag: "Retry" as const, reason: "storage" as const })
707
- : Effect.fail(error("corrupt", "status")),
752
+ ? Effect.succeed({
753
+ _tag: "Retry" as const,
754
+ reason: "storage" as const,
755
+ diagnostic: FailureDiagnostic.capture(failure),
756
+ })
757
+ : Effect.fail(error("corrupt", "status", failure)),
708
758
  ),
709
759
  );
710
760
 
711
761
  if (status._tag === "Unavailable")
712
- return yield* commit({ _tag: "Park", reason: "status-unavailable" });
762
+ return yield* commit({
763
+ _tag: "Park",
764
+ reason: "status-unavailable",
765
+ diagnostic: status.diagnostic,
766
+ });
713
767
  if (status._tag === "Status" && status.status._tag === "settled")
714
768
  return yield* commit({ _tag: "Process", settlement: status.status.settlement });
715
769
  if (status._tag === "Status") return yield* commit({ _tag: "ObservePending" });
716
770
 
717
- return yield* commit({ _tag: "Retry", reason: status.reason });
771
+ return yield* commit({
772
+ _tag: "Retry",
773
+ reason: status.reason,
774
+ diagnostic: status.diagnostic,
775
+ });
718
776
  }),
719
777
  )
720
778
  .pipe(
@@ -1,5 +1,6 @@
1
1
  import { Context, Effect } from "effect";
2
2
 
3
+ import * as FailureDiagnostic from "../core/FailureDiagnostic.ts";
3
4
  import type { Receipt } from "./DurableAgentRuntime.ts";
4
5
  import { type ScheduledInputFailure, ScheduleStorageError } from "./Schedule.ts";
5
6
  import type { SubmissionStatus } from "./SubmissionStatus.ts";
@@ -30,14 +31,26 @@ export const admitPreparedInput = Effect.fn("Thread.admitPreparedInput")(
30
31
  Effect.succeed({ _tag: "Refused" as const, error }),
31
32
  ),
32
33
  Effect.catchTag("ScheduledInputRetryable", (error) =>
33
- Effect.succeed({ _tag: "Retry" as const, reason: error.reason }),
34
+ Effect.succeed({
35
+ _tag: "Retry" as const,
36
+ reason: error.reason,
37
+ diagnostic: FailureDiagnostic.capture(error),
38
+ }),
34
39
  ),
35
- Effect.catchTag("TimeoutError", () =>
36
- Effect.succeed({ _tag: "Retry" as const, reason: "timeout" as const }),
40
+ Effect.catchTag("TimeoutError", (error) =>
41
+ Effect.succeed({
42
+ _tag: "Retry" as const,
43
+ reason: "timeout" as const,
44
+ diagnostic: FailureDiagnostic.capture(error),
45
+ }),
37
46
  ),
38
47
  Effect.catchTag("ScheduleStorageError", (error) =>
39
48
  error.reason === "unavailable"
40
- ? Effect.succeed({ _tag: "Retry" as const, reason: "storage" as const })
49
+ ? Effect.succeed({
50
+ _tag: "Retry" as const,
51
+ reason: "storage" as const,
52
+ diagnostic: FailureDiagnostic.capture(error),
53
+ })
41
54
  : Effect.fail(ScheduleStorageError.make(error)),
42
55
  ),
43
56
  ),
@@ -5,6 +5,7 @@ import { InputMessage } from "../capabilities/Messaging.ts";
5
5
  import { PolicyLimit } from "../core/AgentError.ts";
6
6
  import { AgentPolicy } from "../core/AgentPolicy.ts";
7
7
  import { Update } from "../core/AgentUpdates.ts";
8
+ import * as FailureDiagnostic from "../core/FailureDiagnostic.ts";
8
9
  import {
9
10
  AgentId,
10
11
  AttemptId,
@@ -17,7 +18,6 @@ import {
17
18
  ToolCallId,
18
19
  TurnId,
19
20
  } from "../core/Identifiers.ts";
20
- import { strictSchema } from "../core/internal/strict-schema.ts";
21
21
  import { utf8ByteLength } from "../core/internal/utf8.ts";
22
22
  import { IdempotencyKey, Principal } from "../core/Receipt.ts";
23
23
  import { ExhaustedLimit } from "../core/RunEvent.ts";
@@ -82,22 +82,12 @@ export type ProducerEpoch = typeof ProducerEpoch.Type;
82
82
  const BoundedText = Schema.String.check(Schema.isMaxLength(64 * 1024));
83
83
  const BoundedName = Schema.NonEmptyString.check(Schema.isMaxLength(256));
84
84
 
85
- /** Stable, non-empty failure classification carried by a failed durable Settlement. */
86
- const SettlementFailureTag = Schema.NonEmptyString.check(Schema.isMaxLength(256));
87
-
88
- /** Diagnostic text is bounded independently from the broader persisted JSON envelope. */
89
- const SettlementFailureMessage = Schema.String.check(Schema.isMaxLength(16 * 1024));
90
-
91
85
  /**
92
- * The complete generic diagnostic allowed on a failed durable Settlement. It deliberately has
93
- * no raw Cause, stack, provider payload, or application-specific fields; those values can carry
94
- * secrets and do not form a stable cross-process contract.
86
+ * Private failed-Settlement evidence. The summary remains the safe public projection; diagnostic
87
+ * and context preserve structured causal evidence for authorized operators, never model context.
88
+ * Optional fields allow reading supported Settlements written before causal capture was available.
95
89
  */
96
- export const SettlementFailureDiagnostic = Schema.Struct({
97
- errorTag: SettlementFailureTag,
98
- message: SettlementFailureMessage,
99
- }).pipe(
100
- strictSchema,
90
+ export const SettlementFailureDiagnostic = FailureDiagnostic.Failure.pipe(
101
91
  Schema.annotate({
102
92
  identifier: "@effect-agent/thread/SettlementFailureDiagnostic",
103
93
  }),
@@ -1,5 +1,6 @@
1
1
  import { Context, Effect, Schema } from "effect";
2
2
 
3
+ import * as FailureDiagnostic from "../core/FailureDiagnostic.ts";
3
4
  import { AgentId, ThreadId } from "../core/Identifiers.ts";
4
5
  import { Receipt } from "../core/Receipt.ts";
5
6
  import { DefinitionDigests, Digest, PersistedJson } from "./Records.ts";
@@ -269,13 +270,21 @@ export class ScheduleStorageError extends Schema.TaggedError<ScheduleStorageErro
269
270
  /** Only when the unchanged envelope was not admitted and cannot succeed, including on replay. */
270
271
  export class ScheduledInputRefused extends Schema.TaggedError<ScheduledInputRefused>()(
271
272
  "ScheduledInputRefused",
272
- { code: Name },
273
+ {
274
+ code: Name,
275
+ cause: Schema.optionalKey(FailureDiagnostic.Value),
276
+ stack: Schema.optionalKey(Schema.String),
277
+ },
273
278
  ) {}
274
279
 
275
280
  /** Includes lost replies: admission may already have committed. */
276
281
  export class ScheduledInputRetryable extends Schema.TaggedError<ScheduledInputRetryable>()(
277
282
  "ScheduledInputRetryable",
278
- { reason: ScheduleRetryReason },
283
+ {
284
+ reason: ScheduleRetryReason,
285
+ cause: Schema.optionalKey(FailureDiagnostic.Value),
286
+ stack: Schema.optionalKey(Schema.String),
287
+ },
279
288
  ) {}
280
289
 
281
290
  export type ScheduledInputFailure =
@@ -59,11 +59,23 @@ const Scan = Schema.Struct({
59
59
 
60
60
  const codec = Schema.fromJsonString(MessageDeliveryRecord);
61
61
  const bytes = (text: string): number => new TextEncoder().encode(text).byteLength;
62
- const storage = (operation: string) => MessageDeliveryError.make({ reason: "storage", operation });
63
- const corrupt = (operation: string) => MessageDeliveryError.make({ reason: "corrupt", operation });
62
+
63
+ const storage = (operation: string, cause?: unknown) =>
64
+ MessageDeliveryError.make({
65
+ reason: "storage",
66
+ operation,
67
+ ...(cause === undefined ? {} : { cause }),
68
+ });
69
+
70
+ const corrupt = (operation: string, cause?: unknown) =>
71
+ MessageDeliveryError.make({
72
+ reason: "corrupt",
73
+ operation,
74
+ ...(cause === undefined ? {} : { cause }),
75
+ });
64
76
 
65
77
  const query = <A>(operation: string, effect: Effect.Effect<A, SqlError>) =>
66
- effect.pipe(Effect.mapError(() => storage(operation)));
78
+ effect.pipe(Effect.mapError((cause) => storage(operation, cause)));
67
79
 
68
80
  /**
69
81
  * Shared SQL implementation over the adapter-owned effect_agent_message_deliveries table.
@@ -92,7 +104,7 @@ export const makeSqlMessageDeliveryStore = Effect.fn("SqlMessageDeliveryStore.ma
92
104
  record: MessageDeliveryRecord,
93
105
  ) {
94
106
  const text = yield* Schema.encodeEffect(codec)(record).pipe(
95
- Effect.mapError(() => corrupt("encode")),
107
+ Effect.mapError((cause) => corrupt("encode", cause)),
96
108
  );
97
109
 
98
110
  if (bytes(text) > maxStoredValueBytes)
@@ -108,7 +120,7 @@ export const makeSqlMessageDeliveryStore = Effect.fn("SqlMessageDeliveryStore.ma
108
120
  if (bytes(row.record_json) > maxStoredValueBytes) return yield* corrupt("stored-value-bytes");
109
121
 
110
122
  const record = yield* Schema.decodeEffect(codec)(row.record_json).pipe(
111
- Effect.mapError(() => corrupt("decode")),
123
+ Effect.mapError((cause) => corrupt("decode", cause)),
112
124
  );
113
125
 
114
126
  if (
@@ -126,7 +138,7 @@ export const makeSqlMessageDeliveryStore = Effect.fn("SqlMessageDeliveryStore.ma
126
138
 
127
139
  const decodeRows = (rows: unknown) =>
128
140
  Schema.decodeUnknownEffect(Schema.Array(Row))(rows).pipe(
129
- Effect.mapError(() => corrupt("rows")),
141
+ Effect.mapError((cause) => corrupt("rows", cause)),
130
142
  Effect.flatMap((rows) => Effect.forEach(rows, decode)),
131
143
  );
132
144
 
@@ -149,7 +161,7 @@ export const makeSqlMessageDeliveryStore = Effect.fn("SqlMessageDeliveryStore.ma
149
161
  const text = yield* encode(record);
150
162
 
151
163
  const input = yield* Schema.decodeEffect(codec)(text).pipe(
152
- Effect.mapError(() => corrupt("insert")),
164
+ Effect.mapError((cause) => corrupt("insert", cause)),
153
165
  );
154
166
 
155
167
  if (
@@ -190,7 +202,7 @@ export const makeSqlMessageDeliveryStore = Effect.fn("SqlMessageDeliveryStore.ma
190
202
  );
191
203
 
192
204
  const count = (yield* Schema.decodeUnknownEffect(Schema.Array(Count))(counts).pipe(
193
- Effect.mapError(() => corrupt("count")),
205
+ Effect.mapError((cause) => corrupt("count", cause)),
194
206
  ))[0];
195
207
 
196
208
  if (count === undefined) return yield* corrupt("count");
@@ -293,7 +305,7 @@ export const makeSqlMessageDeliveryStore = Effect.fn("SqlMessageDeliveryStore.ma
293
305
  );
294
306
 
295
307
  const decoded = yield* Schema.decodeUnknownEffect(Schema.Array(Deadline))(rows).pipe(
296
- Effect.mapError(() => corrupt("next-deadline")),
308
+ Effect.mapError((cause) => corrupt("next-deadline", cause)),
297
309
  );
298
310
 
299
311
  return decoded[0]?.deadline ?? null;
@@ -2,6 +2,7 @@ import type { Option, Stream } from "effect";
2
2
  import { Context, Duration, Effect, Schema } from "effect";
3
3
 
4
4
  import { InputMessage } from "../capabilities/Messaging.ts";
5
+ import * as FailureDiagnostic from "../core/FailureDiagnostic.ts";
5
6
  import {
6
7
  AgentId,
7
8
  AttemptId,
@@ -133,6 +134,8 @@ export class AdmissionPolicyError extends Schema.TaggedError<AdmissionPolicyErro
133
134
  {
134
135
  reason: Schema.Literals(["refused", "unavailable", "occupied"]),
135
136
  code: Schema.NonEmptyString.check(Schema.isMaxLength(128)),
137
+ cause: Schema.optionalKey(FailureDiagnostic.Value),
138
+ stack: Schema.optionalKey(Schema.String),
136
139
  },
137
140
  ) {}
138
141
 
@@ -916,7 +919,7 @@ export class ChildReservationConflict extends Schema.TaggedError<ChildReservatio
916
919
  export class LedgerError extends Schema.TaggedError<LedgerError>()("LedgerError", {
917
920
  operation: Schema.String,
918
921
  message: Schema.String,
919
- cause: Schema.optionalKey(Schema.Defect()),
922
+ cause: Schema.optionalKey(FailureDiagnostic.Value),
920
923
  }) {}
921
924
 
922
925
  export type SubmissionLedgerFailure =
@@ -1,4 +1,14 @@
1
- import { type Crypto, type Option, type Scope, Context, Effect, Layer, Schema } from "effect";
1
+ import {
2
+ type Crypto,
3
+ type Option,
4
+ type Scope,
5
+ Context,
6
+ Effect,
7
+ Layer,
8
+ References,
9
+ Schema,
10
+ Tracer,
11
+ } from "effect";
2
12
  import { Tool } from "effect/unstable/ai";
3
13
 
4
14
  import type * as Agent from "../../core/Agent.ts";
@@ -229,20 +239,40 @@ type ReportRequirements<Reports> =
229
239
  : never
230
240
  : never;
231
241
 
242
+ // Registrations outlive their construction span. Dependencies remain captured,
243
+ // while every attempt/report inherits the invoking fiber's tracing state.
244
+ const omitTraceContext = Context.omit(
245
+ Tracer.ParentSpan,
246
+ Tracer.Tracer,
247
+ Tracer.MinimumTraceLevel,
248
+ Tracer.CurrentTraceLevel,
249
+ References.TracerEnabled,
250
+ References.TracerTimingEnabled,
251
+ References.TracerSpanAnnotations,
252
+ References.TracerSpanLinks,
253
+ );
254
+
255
+ // R describes captured application services; ParentSpan is supplied by the
256
+ // live invocation rather than stored as a registration dependency.
257
+ const withoutTraceContext = <R>(context: Context.Context<R>): Context.Context<R> =>
258
+ omitTraceContext(context) as Context.Context<R>;
259
+
232
260
  const captureReporting = <R>(reports: ReadonlyArray<WorkerReporting<unknown, R>>) =>
233
- Effect.map(Effect.context<Exclude<R, Scope.Scope>>(), (context) =>
234
- reports.map((report): WorkerReporting<WorkerReportPreparationFailure> => ({
235
- ...report,
236
- prepare: (value) =>
237
- Effect.scoped(Effect.suspend(() => report.prepare(value))).pipe(
238
- Effect.provide(context),
239
- Effect.mapError((error) =>
240
- Schema.is(WorkerReportPreparationFailure)(error)
241
- ? error
242
- : WorkerReportPreparationFailure.make({ stage: "preparation" }),
261
+ Effect.map(
262
+ Effect.context<Exclude<R, Scope.Scope>>().pipe(Effect.map(withoutTraceContext)),
263
+ (context) =>
264
+ reports.map((report): WorkerReporting<WorkerReportPreparationFailure> => ({
265
+ ...report,
266
+ prepare: (value) =>
267
+ Effect.scoped(Effect.suspend(() => report.prepare(value))).pipe(
268
+ Effect.provide(context),
269
+ Effect.mapError((error) =>
270
+ Schema.is(WorkerReportPreparationFailure)(error)
271
+ ? error
272
+ : WorkerReportPreparationFailure.make({ stage: "preparation" }),
273
+ ),
243
274
  ),
244
- ),
245
- })),
275
+ })),
246
276
  );
247
277
 
248
278
  const backgroundReports = (definition: Agent.AnyDefinition) => [
@@ -276,7 +306,9 @@ const capture = <A extends ExecutableAgentBinding, Provides = never, Requires =
276
306
  Exclude<DurableWorkerRequirements<A>, Provides> | Requires
277
307
  > =>
278
308
  Effect.map(
279
- Effect.context<Exclude<DurableWorkerRequirements<A>, Provides> | Requires>(),
309
+ Effect.context<Exclude<DurableWorkerRequirements<A>, Provides> | Requires>().pipe(
310
+ Effect.map(withoutTraceContext),
311
+ ),
280
312
  (context): CapturedBinding => ({
281
313
  agentId: agent.definition.id,
282
314
  definition: agent.definition,