@effect-agent/platform-cloudflare 0.1.0-beta.15 → 0.1.0-beta.16
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.d.mts +142 -73
- package/dist/index.mjs +148 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/bindings.ts +4 -0
- package/src/client.ts +150 -2
- package/src/conversation-object.ts +63 -42
- package/src/index.ts +1 -0
- package/src/layers.ts +18 -2
- package/src/progress-wait.ts +103 -0
- package/src/wake-scheduler.ts +5 -2
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)
|
|
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
|
-
}))
|
|
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)
|
|
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)
|
|
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
|
-
|
|
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
|