@effect-agent/platform-cloudflare 0.1.0-beta.15 → 0.1.0-beta.17

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/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { Cause, Clock, Context, Duration, Effect, Exit, Fiber, Layer, Option, PubSub, Random, Ref, Schema, Semaphore, Stream } from "effect";
2
- import { AbortCommand, AbortIntent, AdmissionConflict, AgentBindingResolver, AppendConflict, ApprovalConflict, ApprovalDecisionCommand, ApprovalDecisionIntent, CanonicalRecordEnvelope, CanonicalSequence, ConversationNotMaterialized, ConversationRead, ConversationStore, ConversationStoreError, DEFAULT_OWNERSHIP_LEASE_DURATION, DefinitionDigests, DeploymentId, DigestError, DurableAgentRuntime, DurableRuntimeConfig, DurableRuntimeFailpoint, DurableRuntimeFailpointError, FenceRejected, IdempotencyKey, IntegrityReport, JoinedToHost, LedgerError, ObligationReport, ObligationThresholds, OperationAuthorizationRequest, OperationAuthorizer, OperationDenied, OwnershipLost, PersistedJson, Principal, ProducerId, Receipt, RecoveryExplanation, RecoveryReport, RetryCommand, RetryRefused, RunJournalError, Settlement, SettlementConflict, SubmissionLedger, SubmissionLookupByKey, ToolReconciler, UnknownResolutionCommand, UnknownResolutionConflict, UnknownResolutionIntent, WakeScheduler } from "@effect-agent/session";
1
+ import { Cause, Clock, Context, Crypto, Deferred, Duration, Effect, Exit, Fiber, Layer, Option, PubSub, Random, Ref, Schema, Semaphore, Stream } from "effect";
2
+ import { AbortCommand, AbortIntent, AdmissionConflict, AgentBindingResolver, AppendConflict, ApprovalConflict, ApprovalDecisionCommand, ApprovalDecisionIntent, CanonicalRecordEnvelope, CanonicalSequence, ConversationNotMaterialized, ConversationRead, ConversationStore, ConversationStoreError, DEFAULT_OWNERSHIP_LEASE_DURATION, DefinitionDigests, DeploymentId, DigestError, DurableAgentRuntime, DurableRuntimeConfig, DurableRuntimeFailpoint, DurableRuntimeFailpointError, FenceRejected, IdempotencyKey, IntegrityReport, JoinedToHost, LedgerError, ObligationReport, ObligationThresholds, OperationAuthorizationRequest, OperationAuthorizer, OperationDenied, OwnershipLost, PersistedJson, Principal, ProducerId, Receipt, RecoveryExplanation, RecoveryReport, RetryCommand, RetryRefused, RunJournalError, Settlement, SettlementConflict, SubmissionLedger, SubmissionLookupByKey, ToolReconciler, UnknownResolutionCommand, UnknownResolutionConflict, UnknownResolutionIntent, WakeScheduler, makeWakeSubscriptionHub, operationAuthorizerLayer } from "@effect-agent/session";
3
3
  import { ConversationPortTransport, DEFAULT_MAX_STORED_VALUE_BYTES, conversationStoreLayer, handleEncodedPortRequest, portTransportFailure, routedConversationStoreLayer, routedSubmissionLedgerLayer, storageConfigLayer, storageFailpointLayer, submissionLedgerLayer } from "@effect-agent/storage-cloudflare";
4
4
  import { AgentId, AgentInputError, ConversationId, SubmissionId } from "@effect-agent/core";
5
5
  import { BrowserCrypto } from "@effect/platform-browser";
@@ -497,8 +497,9 @@ const cloudflareWakeSchedulerLayer = Layer.effect(WakeScheduler)(Effect.gen(func
497
497
  const identity = yield* ConversationObjectIdentity;
498
498
  const { namespace } = yield* ConversationObjectNamespace;
499
499
  const hints = yield* PubSub.sliding(WAKE_BUFFER_CAPACITY);
500
+ const progress = yield* makeWakeSubscriptionHub;
500
501
  yield* Effect.addFinalizer(() => PubSub.shutdown(hints));
501
- const notifyLocal = (conversationId) => PubSub.publish(hints, conversationId).pipe(Effect.andThen(alarm.scheduleNow), Effect.catch((error) => Effect.logWarning("CloudflareWakeScheduler: local alarm wake failed", error)), Effect.asVoid);
502
+ const notifyLocal = (conversationId) => progress.notify(conversationId).pipe(Effect.andThen(PubSub.publish(hints, conversationId)), Effect.andThen(alarm.scheduleNow), Effect.catch((error) => Effect.logWarning("CloudflareWakeScheduler: local alarm wake failed", error)), Effect.asVoid);
502
503
  const notifyRemote = (conversationId) => Effect.tryPromise({
503
504
  try: () => namespace.get(namespace.idFromName(conversationId)).wake(),
504
505
  catch: (cause) => RemoteWakeDropped.make({
@@ -509,10 +510,76 @@ const cloudflareWakeSchedulerLayer = Layer.effect(WakeScheduler)(Effect.gen(func
509
510
  }).pipe(Effect.catch((error) => Effect.logWarning(`CloudflareWakeScheduler: remote wake of ${conversationId} dropped`, error)), Effect.asVoid);
510
511
  return WakeScheduler.of({
511
512
  notify: (conversationId) => conversationId === identity.conversationId ? notifyLocal(conversationId) : notifyRemote(conversationId),
513
+ subscribe: progress.subscribe,
512
514
  wakes: Stream.fromPubSub(hints)
513
515
  });
514
516
  }));
515
517
  //#endregion
518
+ //#region src/progress-wait.ts
519
+ /** Cancellation tombstones are bounded hints, never durable authority. */
520
+ const MAX_CANCELLATION_TOMBSTONES = 1024;
521
+ /**
522
+ * Per-incarnation cancellation registry for long-lived progress RPCs. The public runtime owns
523
+ * the actual wake registration; this host-only registry lets an interrupted Worker Effect ask
524
+ * the Object to interrupt its scoped wait before the Worker execution context itself ends.
525
+ */
526
+ var ProgressWaitRegistry = class ProgressWaitRegistry extends Context.Service()("@effect-agent/platform-cloudflare/ProgressWaitRegistry") {
527
+ static layer = Layer.effect(ProgressWaitRegistry, Effect.gen(function* () {
528
+ const registrations = yield* Ref.make(/* @__PURE__ */ new Map());
529
+ const remove = (waiterId, deferred) => Ref.update(registrations, (current) => {
530
+ const existing = current.get(waiterId);
531
+ if (existing === void 0 || existing === "cancelled" || !existing.has(deferred)) return current;
532
+ const next = new Map(current);
533
+ const active = new Set(existing);
534
+ active.delete(deferred);
535
+ if (active.size === 0) next.delete(waiterId);
536
+ else next.set(waiterId, active);
537
+ return next;
538
+ });
539
+ const subscribe = Effect.fn("ProgressWaitRegistry.subscribe")((waiterId) => Effect.gen(function* () {
540
+ const deferred = yield* Deferred.make();
541
+ yield* Effect.addFinalizer(() => remove(waiterId, deferred));
542
+ return {
543
+ cancelled: yield* Ref.modify(registrations, (current) => {
544
+ const existing = current.get(waiterId);
545
+ const next = new Map(current);
546
+ if (existing === "cancelled") return [true, current];
547
+ const active = new Set(existing ?? []);
548
+ active.add(deferred);
549
+ next.set(waiterId, active);
550
+ return [false, next];
551
+ }),
552
+ deferred
553
+ };
554
+ }).pipe(Effect.map(({ cancelled, deferred }) => cancelled ? Effect.void : Deferred.await(deferred))));
555
+ const cancel = Effect.fn("ProgressWaitRegistry.cancel")(function* (waiterId) {
556
+ const waiters = yield* Ref.modify(registrations, (current) => {
557
+ const existing = current.get(waiterId);
558
+ const next = new Map(current);
559
+ if (existing === void 0) {
560
+ next.set(waiterId, "cancelled");
561
+ let tombstones = 0;
562
+ for (const registration of next.values()) if (registration === "cancelled") tombstones += 1;
563
+ if (tombstones > MAX_CANCELLATION_TOMBSTONES) for (const [id, registration] of next) {
564
+ if (registration !== "cancelled") continue;
565
+ next.delete(id);
566
+ break;
567
+ }
568
+ return [[], next];
569
+ }
570
+ if (existing === "cancelled") return [[], current];
571
+ next.delete(waiterId);
572
+ return [[...existing], next];
573
+ });
574
+ yield* Effect.forEach(waiters, (waiter) => Deferred.succeed(waiter, void 0), { discard: true });
575
+ });
576
+ return ProgressWaitRegistry.of({
577
+ subscribe,
578
+ cancel
579
+ });
580
+ }));
581
+ };
582
+ //#endregion
516
583
  //#region src/transport.ts
517
584
  /**
518
585
  * `ConversationPortTransport` over native Durable Object JS RPC (decision D-P6-3): one
@@ -643,14 +710,15 @@ var CloudflareDurableRuntime = class {
643
710
  const runtimeFailpointLayer = options.runtimeFailpoint === void 0 ? DurableRuntimeFailpoint.layer : Layer.succeed(DurableRuntimeFailpoint)({ hit: options.runtimeFailpoint(ctx) });
644
711
  const maintenanceFailpointLayer = options.maintenanceFailpoint === void 0 ? ConversationMaintenanceFailpoint.layer : Layer.succeed(ConversationMaintenanceFailpoint)({ hit: options.maintenanceFailpoint(ctx) });
645
712
  const reconcilerLayer = options.toolReconciler ?? ToolReconciler.uncertain;
713
+ const authorizerLayer = options.operationAuthorizer === void 0 ? Layer.empty : operationAuthorizerLayer(options.operationAuthorizer);
646
714
  const bindingResolverLayer = Layer.effect(AgentBindingResolver)(Effect.map(resolveBindings(options.bindings, {
647
715
  ctx,
648
716
  env,
649
717
  conversationId,
650
718
  producerId
651
719
  }), (bindings) => AgentBindingResolver.fromBindings(bindings)));
652
- const base = Layer.mergeAll(identityLayer, cloudflareConfigLayer, DurableAlarmService.layer, maintenanceFailpointLayer);
653
- const runtimeStack = DurableAgentRuntime.layer.pipe(Layer.provideMerge(routedPorts), Layer.provideMerge(cloudflareWakeSchedulerLayer), Layer.provideMerge(runtimeConfigLayer), Layer.provideMerge(bindingResolverLayer), Layer.provide(Layer.mergeAll(runtimeFailpointLayer, reconcilerLayer, BrowserCrypto.layer)), Layer.provideMerge(base));
720
+ const base = Layer.mergeAll(identityLayer, cloudflareConfigLayer, DurableAlarmService.layer, maintenanceFailpointLayer, ProgressWaitRegistry.layer);
721
+ const runtimeStack = DurableAgentRuntime.layer.pipe(Layer.provideMerge(routedPorts), Layer.provideMerge(cloudflareWakeSchedulerLayer), Layer.provideMerge(runtimeConfigLayer), Layer.provideMerge(bindingResolverLayer), Layer.provide(Layer.mergeAll(runtimeFailpointLayer, reconcilerLayer, authorizerLayer, BrowserCrypto.layer)), Layer.provideMerge(base));
654
722
  return Layer.mergeAll(runtimeStack, ConversationMaintenance.layer.pipe(Layer.provide(runtimeStack)), portsEndpointLayer);
655
723
  }));
656
724
  }
@@ -679,7 +747,11 @@ var HostProtocolError = class extends Schema.TaggedError()("HostProtocolError",
679
747
  var ConversationClientError = class extends Schema.TaggedError()("ConversationClientError", {
680
748
  conversationId: Schema.String,
681
749
  message: Schema.String,
682
- cause: Schema.optionalKey(Schema.Defect())
750
+ cause: Schema.optionalKey(Schema.Defect()),
751
+ /** Cloudflare's own classification for a failure safe to retry with a fresh stub. */
752
+ retryable: Schema.optionalKey(Schema.Boolean),
753
+ /** Cloudflare overloads are surfaced immediately instead of adding retry pressure. */
754
+ overloaded: Schema.optionalKey(Schema.Boolean)
683
755
  }) {};
684
756
  /**
685
757
  * One durable submission, input ALREADY encoded by the caller through the Agent Binding's
@@ -699,6 +771,13 @@ var ObservePageRequest = class extends Schema.Class("@effect-agent/platform-clou
699
771
  afterSequence: Schema.optionalKey(CanonicalSequence),
700
772
  limit: Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(1024))
701
773
  }) {};
774
+ /** One event-driven wait for canonical progress strictly after this sequence. */
775
+ var AwaitProgressRequest = class extends Schema.Class("@effect-agent/platform-cloudflare/AwaitProgressRequest")({
776
+ afterSequence: CanonicalSequence,
777
+ waiterId: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(256))
778
+ }) {};
779
+ /** Best-effort cancellation of one in-flight progress RPC. */
780
+ var CancelProgressRequest = class extends Schema.Class("@effect-agent/platform-cloudflare/CancelProgressRequest")({ waiterId: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(256)) }) {};
702
781
  /**
703
782
  * Every typed failure a host entry point can produce, plus the protocol's own errors. Same
704
783
  * closed-union discipline as the WP2 `PortFailure`: members re-decode to the SAME tagged
@@ -721,11 +800,15 @@ const HostFailure = Schema.Union([
721
800
  DurableRuntimeFailpointError,
722
801
  AdmissionLimitExceeded,
723
802
  DurableAlarmError,
803
+ OperationDenied,
724
804
  HostProtocolError
725
805
  ]);
726
806
  var SubmitSucceeded = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/SubmitSucceeded")("SubmitSucceeded", { receipt: Receipt }) {};
727
807
  var SettlementReached = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/SettlementReached")("SettlementReached", { settlement: Settlement }) {};
728
808
  var ObservedPage = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/ObservedPage")("ObservedPage", { records: Schema.Array(CanonicalRecordEnvelope).check(Schema.isMaxLength(1024)) }) {};
809
+ /** A record was already committed or an incarnation-local hint says the caller should re-read. */
810
+ var ProgressObserved = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/ProgressObserved")("ProgressObserved", {}) {};
811
+ var ProgressCancelled = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/ProgressCancelled")("ProgressCancelled", {}) {};
729
812
  var AbortRecorded = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/AbortRecorded")("AbortRecorded", { intent: AbortIntent }) {};
730
813
  var ApprovalRecorded = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/ApprovalRecorded")("ApprovalRecorded", { intent: ApprovalDecisionIntent }) {};
731
814
  var UnknownResolutionRecorded = class extends Schema.TaggedClass("@effect-agent/platform-cloudflare/UnknownResolutionRecorded")("UnknownResolutionRecorded", { intent: UnknownResolutionIntent }) {};
@@ -736,6 +819,8 @@ const HostResponse = Schema.Union([
736
819
  SubmitSucceeded,
737
820
  SettlementReached,
738
821
  ObservedPage,
822
+ ProgressObserved,
823
+ ProgressCancelled,
739
824
  AbortRecorded,
740
825
  ApprovalRecorded,
741
826
  UnknownResolutionRecorded,
@@ -747,6 +832,10 @@ const decodeReceipt = Schema.decodeUnknownEffect(Receipt);
747
832
  const encodeReceipt = Schema.encodeEffect(Receipt);
748
833
  const decodeObservePageRequest = Schema.decodeUnknownEffect(ObservePageRequest);
749
834
  const encodeObservePageRequest = Schema.encodeEffect(ObservePageRequest);
835
+ const decodeAwaitProgressRequest = Schema.decodeUnknownEffect(AwaitProgressRequest);
836
+ const encodeAwaitProgressRequest = Schema.encodeEffect(AwaitProgressRequest);
837
+ const decodeCancelProgressRequest = Schema.decodeUnknownEffect(CancelProgressRequest);
838
+ const encodeCancelProgressRequest = Schema.encodeEffect(CancelProgressRequest);
750
839
  const decodeAbortCommand = Schema.decodeUnknownEffect(AbortCommand);
751
840
  const encodeAbortCommand = Schema.encodeEffect(AbortCommand);
752
841
  const decodeApprovalDecisionCommand = Schema.decodeUnknownEffect(ApprovalDecisionCommand);
@@ -777,8 +866,10 @@ const AWAIT_FAILURE_TAGS = /* @__PURE__ */ new Set([
777
866
  const OBSERVE_FAILURE_TAGS = /* @__PURE__ */ new Set([
778
867
  "ConversationStoreError",
779
868
  "ConversationNotMaterialized",
869
+ "OperationDenied",
780
870
  "HostProtocolError"
781
871
  ]);
872
+ const PROGRESS_FAILURE_TAGS = OBSERVE_FAILURE_TAGS;
782
873
  const ABORT_FAILURE_TAGS = /* @__PURE__ */ new Set([
783
874
  "LedgerError",
784
875
  "SettlementConflict",
@@ -791,6 +882,7 @@ const APPROVAL_FAILURE_TAGS = /* @__PURE__ */ new Set([
791
882
  "LedgerError",
792
883
  "SettlementConflict",
793
884
  "ApprovalConflict",
885
+ "OperationDenied",
794
886
  "DurableAlarmError",
795
887
  "HostProtocolError"
796
888
  ]);
@@ -800,6 +892,7 @@ const UNKNOWN_FAILURE_TAGS = /* @__PURE__ */ new Set([
800
892
  "UnknownResolutionConflict",
801
893
  "JoinedToHost",
802
894
  "DurableRuntimeFailpointError",
895
+ "OperationDenied",
803
896
  "DurableAlarmError",
804
897
  "HostProtocolError"
805
898
  ]);
@@ -818,12 +911,27 @@ const narrowFailure = (tags) => (failure) => tags.has(failure._tag);
818
911
  var CloudflareConversationClient = class CloudflareConversationClient extends Context.Service()("@effect-agent/platform-cloudflare/CloudflareConversationClient") {
819
912
  static layer = Layer.effect(CloudflareConversationClient)(Effect.gen(function* () {
820
913
  const { namespace } = yield* ConversationObjectNamespace;
914
+ const crypto = yield* Crypto.Crypto;
915
+ const platformSignals = (cause) => {
916
+ let retryable;
917
+ let overloaded;
918
+ if (typeof cause === "object" && cause !== null) {
919
+ if ("retryable" in cause && typeof cause.retryable === "boolean") retryable = cause.retryable;
920
+ if ("overloaded" in cause && typeof cause.overloaded === "boolean") overloaded = cause.overloaded;
921
+ if (retryable === void 0 && "durableObjectReset" in cause && cause.durableObjectReset === true) retryable = true;
922
+ }
923
+ return {
924
+ ...retryable === void 0 ? {} : { retryable },
925
+ ...overloaded === void 0 ? {} : { overloaded }
926
+ };
927
+ };
821
928
  const call = (conversationId, operation, invoke) => Effect.tryPromise({
822
929
  try: () => invoke(namespace.get(namespace.idFromName(conversationId))),
823
930
  catch: (cause) => ConversationClientError.make({
824
931
  conversationId,
825
932
  message: boundHostDiagnostic(`${operation} did not reach the Conversation Object: ${cause instanceof Error ? cause.message : String(cause)}`),
826
- cause
933
+ cause,
934
+ ...platformSignals(cause)
827
935
  })
828
936
  }).pipe(Effect.flatMap((raw) => decodeHostResponse(raw).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`The ${operation} answer could not be decoded: ${error.message}`) })))), Effect.withSpan("CloudflareConversationClient.call", { attributes: {
829
937
  conversationId,
@@ -849,6 +957,7 @@ var CloudflareConversationClient = class CloudflareConversationClient extends Co
849
957
  const response = yield* call(conversationId, "observePage", (stub) => stub.observePage(encoded));
850
958
  return (yield* expect(conversationId, "observePage", "ObservedPage", OBSERVE_FAILURE_TAGS)(response)).records;
851
959
  });
960
+ const cancelProgress = (conversationId, waiterId) => encodeCancelProgressRequest(CancelProgressRequest.make({ waiterId })).pipe(Effect.mapError(() => void 0), Effect.flatMap((encoded) => call(conversationId, "cancelProgress", (stub) => stub.cancelProgressEncoded(encoded))), Effect.asVoid, Effect.ignore);
852
961
  return CloudflareConversationClient.of({
853
962
  submit: (agent, input, options) => Effect.gen(function* () {
854
963
  const encodedInput = yield* Schema.encodeEffect(agent.definition.input)(input).pipe(Effect.mapError((cause) => AgentInputError.make({ message: `Unable to encode Agent input: ${cause.message}` })));
@@ -869,6 +978,16 @@ var CloudflareConversationClient = class CloudflareConversationClient extends Co
869
978
  const response = yield* call(receipt.conversationId, "awaitSettlement", (stub) => stub.awaitSettlementEncoded(encoded));
870
979
  return (yield* expect(receipt.conversationId, "awaitSettlement", "SettlementReached", AWAIT_FAILURE_TAGS)(response)).settlement;
871
980
  }),
981
+ awaitProgress: (conversationId, afterSequence) => Effect.gen(function* () {
982
+ const waiterId = yield* crypto.randomUUIDv4.pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`awaitProgress cancellation identity generation failed: ${error.message}`) })));
983
+ const request = AwaitProgressRequest.make({
984
+ afterSequence,
985
+ waiterId
986
+ });
987
+ const encoded = yield* encodeAwaitProgressRequest(request).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`awaitProgress request encode failed: ${error.message}`) })));
988
+ const attempt = (retry) => call(conversationId, "awaitProgress", (stub) => stub.awaitProgressEncoded(encoded)).pipe(Effect.flatMap(expect(conversationId, "awaitProgress", "ProgressObserved", PROGRESS_FAILURE_TAGS)), Effect.asVoid, Effect.catchTag("ConversationClientError", (error) => error.retryable === true && error.overloaded !== true && retry < 5 ? Effect.sleep(Duration.millis(10 * 2 ** retry)).pipe(Effect.andThen(attempt(retry + 1))) : Effect.fail(error)));
989
+ yield* attempt(0).pipe(Effect.onInterrupt(() => cancelProgress(conversationId, waiterId)));
990
+ }),
872
991
  readPage,
873
992
  readAll: (conversationId) => Effect.gen(function* () {
874
993
  const all = [];
@@ -997,13 +1116,27 @@ const awaitSettlementEndpoint = (encoded) => decodeReceipt(encoded).pipe(Effect.
997
1116
  const settlement = yield* (yield* DurableAgentRuntime).awaitSettlement(receipt);
998
1117
  return SettlementReached.make({ settlement });
999
1118
  })), respond, Effect.flatMap(encodeResponse));
1119
+ const awaitProgressEndpoint = (encoded) => decodeAwaitProgressRequest(encoded).pipe(Effect.mapError(protocolFailure("The progress request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
1120
+ const identity = yield* ConversationObjectIdentity;
1121
+ const runtime = yield* DurableAgentRuntime;
1122
+ const registry = yield* ProgressWaitRegistry;
1123
+ yield* Effect.scoped(Effect.gen(function* () {
1124
+ const cancelled = yield* registry.subscribe(request.waiterId);
1125
+ yield* Effect.raceFirst(runtime.awaitProgress(identity.conversationId, request.afterSequence), cancelled);
1126
+ }));
1127
+ return ProgressObserved.make();
1128
+ })), respond, Effect.flatMap(encodeResponse));
1129
+ const cancelProgressEndpoint = (encoded) => decodeCancelProgressRequest(encoded).pipe(Effect.mapError(protocolFailure("The progress cancellation could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
1130
+ yield* (yield* ProgressWaitRegistry).cancel(request.waiterId);
1131
+ return ProgressCancelled.make();
1132
+ })), respond, Effect.flatMap(encodeResponse));
1000
1133
  const observePageEndpoint = (encoded) => decodeObservePageRequest(encoded).pipe(Effect.mapError(protocolFailure("The observe request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
1001
1134
  const identity = yield* ConversationObjectIdentity;
1002
1135
  const store = yield* ConversationStore;
1003
1136
  yield* (yield* OperationAuthorizer).authorize(OperationAuthorizationRequest.make({
1004
1137
  operation: "observe",
1005
1138
  conversationId: identity.conversationId
1006
- })).pipe(Effect.catchTag("OperationDenied", deniedToProtocolFailure));
1139
+ }));
1007
1140
  const records = yield* Stream.runCollect(store.read(ConversationRead.make({
1008
1141
  conversationId: identity.conversationId,
1009
1142
  ...request.afterSequence === void 0 ? {} : { afterSequence: request.afterSequence },
@@ -1017,24 +1150,16 @@ const abortEndpoint = (encoded) => decodeAbortCommand(encoded).pipe(Effect.mapEr
1017
1150
  const intent = yield* maintenance.withMutation(runtime.abort(command));
1018
1151
  return AbortRecorded.make({ intent });
1019
1152
  })), respond, Effect.flatMap(encodeResponse));
1020
- /**
1021
- * The pre-P7 host protocol's failure union does not carry `OperationDenied` (the Worker client
1022
- * predates the authorizer). This assembly always runs the default possession authorizer — no
1023
- * `CloudflareDurableRuntimeOptions` authorizer lever exists yet — so a denial here is
1024
- * unreachable today; if one ever surfaces it degrades to the protocol failure instead of an
1025
- * out-of-contract throw. The four P7 admin entry points below carry `OperationDenied` typed.
1026
- */
1027
- const deniedToProtocolFailure = (denied) => Effect.fail(HostProtocolError.make({ message: boundHostDiagnostic(`The ${denied.operation} operation was denied: ${denied.reason}`) }));
1028
1153
  const resolveApprovalEndpoint = (encoded) => decodeApprovalDecisionCommand(encoded).pipe(Effect.mapError(protocolFailure("The approval command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
1029
1154
  const maintenance = yield* ConversationMaintenance;
1030
1155
  const runtime = yield* DurableAgentRuntime;
1031
- const intent = yield* maintenance.withMutation(runtime.resolveApproval(command).pipe(Effect.catchTag("OperationDenied", deniedToProtocolFailure)));
1156
+ const intent = yield* maintenance.withMutation(runtime.resolveApproval(command));
1032
1157
  return ApprovalRecorded.make({ intent });
1033
1158
  })), respond, Effect.flatMap(encodeResponse));
1034
1159
  const resolveUnknownEndpoint = (encoded) => decodeUnknownResolutionCommand(encoded).pipe(Effect.mapError(protocolFailure("The resolution command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
1035
1160
  const maintenance = yield* ConversationMaintenance;
1036
1161
  const runtime = yield* DurableAgentRuntime;
1037
- const intent = yield* maintenance.withMutation(runtime.resolveUnknown(command).pipe(Effect.catchTag("OperationDenied", deniedToProtocolFailure)));
1162
+ const intent = yield* maintenance.withMutation(runtime.resolveUnknown(command));
1038
1163
  return UnknownResolutionRecorded.make({ intent });
1039
1164
  })), respond, Effect.flatMap(encodeResponse));
1040
1165
  /** Explain one Submission (`submissionId` present) or every nonterminal lane member. */
@@ -1128,7 +1253,8 @@ const portCallEndpoint = (encoded) => Effect.gen(function* () {
1128
1253
  return response;
1129
1254
  });
1130
1255
  const wakeEndpoint = Effect.gen(function* () {
1131
- yield* (yield* DurableAlarmService).scheduleNow.pipe(Effect.catch((error) => Effect.logWarning("ConversationObject.wake dropped", error)));
1256
+ const identity = yield* ConversationObjectIdentity;
1257
+ yield* (yield* WakeScheduler).notify(identity.conversationId);
1132
1258
  });
1133
1259
  const alarmEndpoint = Effect.gen(function* () {
1134
1260
  yield* (yield* ConversationMaintenance).pass;
@@ -1177,6 +1303,8 @@ const makeConversationObjectClass = (options, observability) => {
1177
1303
  const rpc = {
1178
1304
  submitEncoded: (encoded) => submitEndpoint(encoded),
1179
1305
  awaitSettlementEncoded: (encoded) => awaitSettlementEndpoint(encoded),
1306
+ awaitProgressEncoded: (encoded) => awaitProgressEndpoint(encoded),
1307
+ cancelProgressEncoded: (encoded) => cancelProgressEndpoint(encoded),
1180
1308
  observePage: (encoded) => observePageEndpoint(encoded),
1181
1309
  abortEncoded: (encoded) => abortEndpoint(encoded),
1182
1310
  resolveApprovalEncoded: (encoded) => resolveApprovalEndpoint(encoded),
@@ -1829,6 +1957,6 @@ const classifyWorkerFailure = (cause, maxWallTime) => {
1829
1957
  /** Layer building the Dynamic Worker `CodeExecutor` from resolved bindings. */
1830
1958
  const dynamicWorkerCodeExecutorLayer = (options) => Layer.succeed(CodeExecutor)(CodeExecutor.of({ execute: makeExecute(options) }));
1831
1959
  //#endregion
1832
- export { AbortRecorded, AdminExplainRequest, AdminFailed, AdminFailure, AdminResponse, AdminVerifyRequest, AdmissionLimitExceeded, ApprovalRecorded, CLOUDFLARE_DATABASE_CAP_BYTES, CLOUDFLARE_RUNTIME_DEFAULTS, CloudflareAdmissionLimitsValue, CloudflareBindingError, CloudflareConversationClient, CloudflareDurableRuntime, CloudflareDurableRuntimeConfig, CloudflareDurableRuntimeConfigValue, CloudflarePlatformConfigError, CodeModeHostEntrypoint, ConversationClientError, ConversationMaintenance, ConversationMaintenanceFailpoint, ConversationObjectIdentity, ConversationObjectNamespace, ConversationObjectPorts, DEFAULT_MAX_DATABASE_BYTES, DurableAlarmError, DurableAlarmService, DurableObjectContext, ExplainedRecovery, HostFailed, HostFailure, HostProtocolError, HostResponse, MaintenancePassReport, ObligationsScanned, ObservePageRequest, ObservedPage, RetryExecuted, SettlementReached, SubmitRequest, SubmitSucceeded, UnknownResolutionRecorded, VerifiedIntegrity, boundHostDiagnostic, cloudflareWakeSchedulerLayer, conversationNamespaceFromEnv, conversationNamespaceLayer, conversationPortTransportLayer, decodeAbortCommand, decodeAdminExplainRequest, decodeAdminResponse, decodeAdminVerifyRequest, decodeApprovalDecisionCommand, decodeHostResponse, decodeObligationThresholds, decodeObservePageRequest, decodeReceipt, decodeRetryCommand, decodeSubmitRequest, decodeUnknownResolutionCommand, dynamicWorkerCodeExecutorLayer, dynamicWorkerImplementation, encodeAbortCommand, encodeAdminResponse, encodeApprovalDecisionCommand, encodeHostResponse, encodeObservePageRequest, encodeReceipt, encodeSubmitRequest, encodeUnknownResolutionCommand, makeConversationObjectClass };
1960
+ export { AbortRecorded, AdminExplainRequest, AdminFailed, AdminFailure, AdminResponse, AdminVerifyRequest, AdmissionLimitExceeded, ApprovalRecorded, AwaitProgressRequest, CLOUDFLARE_DATABASE_CAP_BYTES, CLOUDFLARE_RUNTIME_DEFAULTS, CancelProgressRequest, CloudflareAdmissionLimitsValue, CloudflareBindingError, CloudflareConversationClient, CloudflareDurableRuntime, CloudflareDurableRuntimeConfig, CloudflareDurableRuntimeConfigValue, CloudflarePlatformConfigError, CodeModeHostEntrypoint, ConversationClientError, ConversationMaintenance, ConversationMaintenanceFailpoint, ConversationObjectIdentity, ConversationObjectNamespace, ConversationObjectPorts, DEFAULT_MAX_DATABASE_BYTES, DurableAlarmError, DurableAlarmService, DurableObjectContext, ExplainedRecovery, HostFailed, HostFailure, HostProtocolError, HostResponse, MaintenancePassReport, ObligationsScanned, ObservePageRequest, ObservedPage, ProgressCancelled, ProgressObserved, ProgressWaitRegistry, RetryExecuted, SettlementReached, SubmitRequest, SubmitSucceeded, UnknownResolutionRecorded, VerifiedIntegrity, boundHostDiagnostic, cloudflareWakeSchedulerLayer, conversationNamespaceFromEnv, conversationNamespaceLayer, conversationPortTransportLayer, decodeAbortCommand, decodeAdminExplainRequest, decodeAdminResponse, decodeAdminVerifyRequest, decodeApprovalDecisionCommand, decodeAwaitProgressRequest, decodeCancelProgressRequest, decodeHostResponse, decodeObligationThresholds, decodeObservePageRequest, decodeReceipt, decodeRetryCommand, decodeSubmitRequest, decodeUnknownResolutionCommand, dynamicWorkerCodeExecutorLayer, dynamicWorkerImplementation, encodeAbortCommand, encodeAdminResponse, encodeApprovalDecisionCommand, encodeAwaitProgressRequest, encodeCancelProgressRequest, encodeHostResponse, encodeObservePageRequest, encodeReceipt, encodeSubmitRequest, encodeUnknownResolutionCommand, makeConversationObjectClass };
1833
1961
 
1834
1962
  //# sourceMappingURL=index.mjs.map