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.
- package/dist/{Agent-CM6JubNX.d.mts → Agent-Bk-mLtov.d.mts} +2 -2
- package/dist/{AgentError-CggcAQ7V.d.mts → AgentError-Bn1ytXRD.d.mts} +20 -4
- package/dist/{AgentRuntime-B1SXMVN7.d.mts → AgentRuntime-BEXToYl1.d.mts} +8 -8
- package/dist/{AgentRuntime-BWOnNc0d.mjs → AgentRuntime-e2M5UoXn.mjs} +4 -3
- package/dist/AgentRuntime-e2M5UoXn.mjs.map +1 -0
- package/dist/{DurableAgentRuntime-C9eRZS9N.mjs → DurableAgentRuntime-wd1x0TcB.mjs} +67 -36
- package/dist/DurableAgentRuntime-wd1x0TcB.mjs.map +1 -0
- package/dist/{EventSource-K7XUzurY.d.mts → EventSource-pH-v0k42.d.mts} +3 -3
- package/dist/FailureDiagnostic-BElLOoED.mjs +274 -0
- package/dist/FailureDiagnostic-BElLOoED.mjs.map +1 -0
- package/dist/FailureDiagnostic-CaAkzGHL.d.mts +223 -0
- package/dist/{Messaging-QMYhp297.d.mts → Messaging-Bl4SBKpR.d.mts} +3 -3
- package/dist/{MessagingHost-gAxs5gme.d.mts → MessagingHost-nwBMdRoh.d.mts} +3 -3
- package/dist/{Output-CjocJzsl.d.mts → Output-B6RQ5jRU.d.mts} +2 -2
- package/dist/{PreparedInputAdmission-KLk5rGFI.d.mts → PreparedInputAdmission-D3-BgmA9.d.mts} +8 -4
- package/dist/{Records-Bidb7ByL.d.mts → Records-B4S02MX1.d.mts} +201 -14
- package/dist/{RunJournal-srpbEBEy.mjs → RunJournal-BdIlgAEj.mjs} +2 -2
- package/dist/{RunJournal-srpbEBEy.mjs.map → RunJournal-BdIlgAEj.mjs.map} +1 -1
- package/dist/{RunOptions-Bruk54SE.d.mts → RunOptions-qOcPv08p.d.mts} +10 -5
- package/dist/{Schedule-Cy9up8Uf.d.mts → Schedule-D2TVEu3W.d.mts} +7 -2
- package/dist/{Scheduling-CHCsSCGo.mjs → Scheduling-DPb2QyAK.mjs} +2 -2
- package/dist/{Scheduling-CHCsSCGo.mjs.map → Scheduling-DPb2QyAK.mjs.map} +1 -1
- package/dist/{Subagent-DP0CzO16.d.mts → Subagent-BxuDuCHt.d.mts} +172 -8
- package/dist/{Subagent-C2s8PFrd.mjs → Subagent-uXWHXiKb.mjs} +64 -29
- package/dist/Subagent-uXWHXiKb.mjs.map +1 -0
- package/dist/{SubagentHost-CYcxkpRc.d.mts → SubagentHost-DEPw4YME.d.mts} +6 -3
- package/dist/{Subscription-CHyoQelH.d.mts → Subscription-nX0rz4GQ.d.mts} +3 -3
- package/dist/{SubscriptionInput-DqrHW-Ja.d.mts → SubscriptionInput-CAG3_pyJ.d.mts} +3 -3
- package/dist/{Worker--j87JI__.d.mts → Worker-Bbj9uq5H.d.mts} +5 -2
- package/dist/{agent-registration-ByeHejH3.mjs → agent-registration-B5CI-Ygk.mjs} +7 -5
- package/dist/agent-registration-B5CI-Ygk.mjs.map +1 -0
- package/dist/capabilities/Commands.d.mts +1 -1
- package/dist/capabilities/Messaging.d.mts +2 -2
- package/dist/capabilities/RunHooks.d.mts +1 -1
- package/dist/capabilities/Subagent.d.mts +2 -2
- package/dist/capabilities/Subagent.mjs +1 -1
- package/dist/core/Agent.d.mts +1 -1
- package/dist/core/AgentError.d.mts +2 -2
- package/dist/core/AgentError.mjs +19 -2
- package/dist/core/AgentError.mjs.map +1 -1
- package/dist/core/FailureDiagnostic.d.mts +2 -0
- package/dist/core/FailureDiagnostic.mjs +2 -0
- package/dist/core/Worker.d.mts +1 -1
- package/dist/core/Worker.mjs +4 -1
- package/dist/core/Worker.mjs.map +1 -1
- package/dist/durable/ActivityStore.d.mts +1 -1
- package/dist/durable/ActivityStore.mjs +1 -1
- package/dist/durable/Admin.d.mts +1 -1
- package/dist/durable/Admin.mjs +1 -1
- package/dist/durable/AgentRegistration.d.mts +1 -1
- package/dist/durable/AgentRegistration.mjs +1 -1
- package/dist/durable/Certification.d.mts +1 -1
- package/dist/durable/CommittedActivity.d.mts +1 -1
- package/dist/durable/CommittedActivity.mjs +1 -1
- package/dist/durable/Digest.d.mts +1 -1
- package/dist/durable/Digest.mjs +7 -7
- package/dist/durable/Digest.mjs.map +1 -1
- package/dist/durable/DurableAgentRuntime.d.mts +1 -1
- package/dist/durable/DurableAgentRuntime.mjs +1 -1
- package/dist/durable/EventSource.d.mts +1 -1
- package/dist/durable/EventSource.mjs +1 -1
- package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
- package/dist/durable/GitHubWorkflowSource.mjs +1 -1
- package/dist/durable/MessageDelivery.d.mts +15 -3
- package/dist/durable/MessageDelivery.mjs +44 -24
- package/dist/durable/MessageDelivery.mjs.map +1 -1
- package/dist/durable/MessageDeliveryStoreConformance.d.mts +4 -1
- package/dist/durable/MessageDeliveryStoreConformance.mjs +1 -1
- package/dist/durable/PersistentHistory.d.mts +1 -1
- package/dist/durable/PersistentHistory.mjs +2 -2
- package/dist/durable/PreparedInputAdmission.d.mts +1 -1
- package/dist/durable/PreparedInputAdmission.mjs +8 -4
- package/dist/durable/PreparedInputAdmission.mjs.map +1 -1
- package/dist/durable/Records.d.mts +1 -1
- package/dist/durable/Records.mjs +831 -2
- package/dist/durable/Records.mjs.map +1 -0
- package/dist/durable/Recovery.d.mts +1 -1
- package/dist/durable/Recovery.mjs +1 -1
- package/dist/durable/RunJournal.d.mts +1 -1
- package/dist/durable/RunJournal.mjs +1 -1
- package/dist/durable/Schedule.d.mts +1 -1
- package/dist/durable/Schedule.mjs +12 -3
- package/dist/durable/Schedule.mjs.map +1 -1
- package/dist/durable/ScheduleStoreConformance.d.mts +1 -1
- package/dist/durable/ScheduleStoreConformance.mjs +1 -1
- package/dist/durable/ScheduleTransition.d.mts +1 -1
- package/dist/durable/ScheduleTransition.mjs +1 -1
- package/dist/durable/Scheduling.d.mts +2 -2
- package/dist/durable/Scheduling.mjs +1 -1
- package/dist/durable/SqlMessageDeliveryStore.mjs +13 -11
- package/dist/durable/SqlMessageDeliveryStore.mjs.map +1 -1
- package/dist/durable/SqlStorageV2Upgrade.d.mts +2 -2
- package/dist/durable/SqlStorageV2Upgrade.mjs +1 -1
- package/dist/durable/SqlSubscriptionStore.d.mts +2 -2
- package/dist/durable/SqlSubscriptionStore.mjs +1 -1
- package/dist/durable/SqlThreadNativeReads.d.mts +1 -1
- package/dist/durable/SqlThreadNativeReads.mjs +2 -2
- package/dist/durable/SubmissionLedger.d.mts +1 -1
- package/dist/durable/SubmissionLedger.mjs +6 -3
- package/dist/durable/SubmissionLedger.mjs.map +1 -1
- package/dist/durable/SubmissionLedgerConformance.d.mts +1 -1
- package/dist/durable/SubmissionLedgerConformance.mjs +1 -1
- package/dist/durable/SubmissionStatus.d.mts +1 -1
- package/dist/durable/Subscription.d.mts +1 -1
- package/dist/durable/Subscription.mjs +1 -1
- package/dist/durable/SubscriptionInput.d.mts +1 -1
- package/dist/durable/SubscriptionInput.mjs +2 -2
- package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
- package/dist/durable/SubscriptionStoreConformance.mjs +1 -1
- package/dist/durable/SubscriptionTools.d.mts +3 -3
- package/dist/durable/SubscriptionTransition.d.mts +1 -1
- package/dist/durable/SubscriptionTransition.mjs +1 -1
- package/dist/durable/Subscriptions.d.mts +5 -5
- package/dist/durable/Subscriptions.mjs +1 -1
- package/dist/durable/ThreadContextHistory.d.mts +1 -1
- package/dist/durable/ThreadContextHistory.mjs +1 -1
- package/dist/durable/ThreadContextHistoryProjection.d.mts +1 -1
- package/dist/durable/ThreadContextHistoryProjection.mjs +1 -1
- package/dist/durable/ThreadInvariants.d.mts +1 -1
- package/dist/durable/ThreadInvariants.mjs +2 -2
- package/dist/durable/ThreadProjection.d.mts +1 -1
- package/dist/durable/ThreadProjection.mjs +1 -1
- package/dist/durable/ThreadProjectionMaintenance.d.mts +1 -1
- package/dist/durable/ThreadStore.d.mts +1 -1
- package/dist/durable/ThreadStore.mjs +2 -2
- package/dist/durable/ThreadStoreConformance.d.mts +1 -1
- package/dist/durable/ThreadStoreConformance.mjs +1 -1
- package/dist/durable/ToolReconciler.mjs +1 -1
- package/dist/durable/WorkerHost.d.mts +3 -3
- package/dist/engine/AgentRuntime.d.mts +1 -1
- package/dist/engine/AgentRuntime.mjs +1 -1
- package/dist/engine/MessagingHost.d.mts +1 -1
- package/dist/engine/Output.d.mts +1 -1
- package/dist/engine/RunOptions.d.mts +1 -1
- package/dist/engine/RunOptions.mjs +2 -0
- package/dist/engine/RunOptions.mjs.map +1 -1
- package/dist/engine/SubagentHost.d.mts +1 -1
- package/dist/engine/SubagentHost.mjs.map +1 -1
- package/dist/index.d.mts +18 -17
- package/dist/index.mjs +8 -7
- package/package.json +1 -1
- package/src/capabilities/internal/subagent-background.ts +66 -23
- package/src/capabilities/internal/subagent-contract.ts +4 -0
- package/src/core/AgentError.ts +20 -0
- package/src/core/FailureDiagnostic.ts +343 -0
- package/src/core/Worker.ts +4 -1
- package/src/durable/Digest.ts +22 -28
- package/src/durable/DurableAgentRuntime.ts +37 -13
- package/src/durable/MessageDelivery.ts +82 -24
- package/src/durable/PreparedInputAdmission.ts +17 -4
- package/src/durable/Records.ts +5 -15
- package/src/durable/Schedule.ts +11 -2
- package/src/durable/SqlMessageDeliveryStore.ts +21 -9
- package/src/durable/SubmissionLedger.ts +4 -1
- package/src/durable/internal/agent-registration.ts +46 -14
- package/src/durable/internal/worker-host.ts +32 -19
- package/src/engine/RunOptions.ts +11 -3
- package/src/engine/SubagentHost.ts +3 -0
- package/src/engine/internal/agent-runtime.ts +23 -16
- package/src/index.ts +1 -0
- package/dist/AgentRuntime-BWOnNc0d.mjs.map +0 -1
- package/dist/DurableAgentRuntime-C9eRZS9N.mjs.map +0 -1
- package/dist/Records-D8167fHn.mjs +0 -844
- package/dist/Records-D8167fHn.mjs.map +0 -1
- package/dist/Subagent-C2s8PFrd.mjs.map +0 -1
- 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({
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
707
|
-
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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({
|
|
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
|
),
|
package/src/durable/Records.ts
CHANGED
|
@@ -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
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
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 =
|
|
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
|
}),
|
package/src/durable/Schedule.ts
CHANGED
|
@@ -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
|
-
{
|
|
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
|
-
{
|
|
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
|
-
|
|
63
|
-
const
|
|
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(
|
|
922
|
+
cause: Schema.optionalKey(FailureDiagnostic.Value),
|
|
920
923
|
}) {}
|
|
921
924
|
|
|
922
925
|
export type SubmissionLedgerFailure =
|
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
import {
|
|
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(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
Effect.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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,
|