@effect-agent/platform-cloudflare 0.0.1-beta.4 → 0.0.1-beta.6
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 +145 -47
- package/dist/index.mjs +906 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -11
- package/src/alarm.ts +1 -1
- package/src/bindings.ts +1 -1
- package/src/client.ts +2 -2
- package/src/code-mode-executor.ts +710 -0
- package/src/config.ts +5 -2
- package/src/conversation-object.ts +159 -28
- package/src/index.ts +2 -0
- package/src/layers.ts +56 -19
- package/src/telemetry-internal.ts +432 -0
- package/src/telemetry.ts +37 -0
- package/src/wake-scheduler.ts +1 -1
package/src/config.ts
CHANGED
|
@@ -12,7 +12,7 @@ const PositiveMillis = Schema.Int.check(Schema.isGreaterThan(0));
|
|
|
12
12
|
const NonNegativeMillis = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
13
13
|
|
|
14
14
|
/** The supplied Cloudflare durable runtime configuration failed validation (DEPLOY-003). */
|
|
15
|
-
export class CloudflarePlatformConfigError extends Schema.
|
|
15
|
+
export class CloudflarePlatformConfigError extends Schema.TaggedError<CloudflarePlatformConfigError>()(
|
|
16
16
|
"CloudflarePlatformConfigError",
|
|
17
17
|
{
|
|
18
18
|
message: Schema.String,
|
|
@@ -28,7 +28,7 @@ export class CloudflarePlatformConfigError extends Schema.TaggedErrorClass<Cloud
|
|
|
28
28
|
* Conversation Object's submit entry point before `DurableAgentRuntime.submit` runs, and
|
|
29
29
|
* nothing was admitted or written.
|
|
30
30
|
*/
|
|
31
|
-
export class AdmissionLimitExceeded extends Schema.
|
|
31
|
+
export class AdmissionLimitExceeded extends Schema.TaggedError<AdmissionLimitExceeded>()(
|
|
32
32
|
"AdmissionLimitExceeded",
|
|
33
33
|
{
|
|
34
34
|
limit: Schema.Literals(["queue-depth", "input-bytes", "database-bytes"]),
|
|
@@ -103,6 +103,8 @@ export class CloudflareDurableRuntimeConfigValue extends Schema.Class<Cloudflare
|
|
|
103
103
|
abortPollInterval: PositiveMillis,
|
|
104
104
|
/** Canonical observation poll cadence of the Durable Object store. */
|
|
105
105
|
observationPollInterval: NonNegativeMillis,
|
|
106
|
+
/** Cooperative background-export budget; native Object delivery never awaits the flush. */
|
|
107
|
+
telemetryFlushTimeout: PositiveMillis,
|
|
106
108
|
/** Per-value byte bound; must stay under the platform's 2 MB SQLite value limit. */
|
|
107
109
|
maxStoredValueBytes: Schema.Int.check(
|
|
108
110
|
Schema.isGreaterThan(0),
|
|
@@ -129,6 +131,7 @@ export const CLOUDFLARE_RUNTIME_DEFAULTS = {
|
|
|
129
131
|
leaseRenewalInterval: 10_000,
|
|
130
132
|
abortPollInterval: 500,
|
|
131
133
|
observationPollInterval: 25,
|
|
134
|
+
telemetryFlushTimeout: 2_000,
|
|
132
135
|
maxStoredValueBytes: DEFAULT_MAX_STORED_VALUE_BYTES,
|
|
133
136
|
verifyOnOpen: false,
|
|
134
137
|
maxQueueDepthPerLane: 256,
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
DurableObjectContext,
|
|
39
39
|
conversationNamespaceLayer,
|
|
40
40
|
type CloudflareBindingError,
|
|
41
|
+
type ConversationObjectNamespace,
|
|
41
42
|
} from "./bindings.ts";
|
|
42
43
|
import {
|
|
43
44
|
AbortRecorded,
|
|
@@ -67,9 +68,18 @@ import {
|
|
|
67
68
|
type CloudflareDurableRuntimeOptions,
|
|
68
69
|
type CloudflareDurableRuntimeServices,
|
|
69
70
|
} from "./layers.ts";
|
|
71
|
+
import {
|
|
72
|
+
flushCloudflareRuntimeTelemetry,
|
|
73
|
+
logCloudflareWaitUntilRegistrationFailure,
|
|
74
|
+
makeCloudflareTelemetryFlushCoordinator,
|
|
75
|
+
registerCloudflareTelemetryAfterNativeSettlement,
|
|
76
|
+
withCloudflareNativeSpanFailure,
|
|
77
|
+
type CloudflareTelemetryFlushCoordinator,
|
|
78
|
+
} from "./telemetry-internal.ts";
|
|
79
|
+
import { CloudflareRuntimeTelemetry } from "./telemetry.ts";
|
|
70
80
|
|
|
71
81
|
/**
|
|
72
|
-
* `makeConversationObjectClass(options)` — the Conversation Durable Object (plan §1.4,
|
|
82
|
+
* `makeConversationObjectClass(options, telemetry?)` — the Conversation Durable Object (plan §1.4,
|
|
73
83
|
* D-P6-1): a factory returning a class that applications export from their Worker entry.
|
|
74
84
|
* One SQLite-backed Object per Conversation is the serialized owner (durability §6); the
|
|
75
85
|
* Object never runs `runResolvedWorker`'s infinite loop — each ingress event or alarm runs
|
|
@@ -95,9 +105,15 @@ export interface ConversationObjectOptions extends CloudflareDurableRuntimeOptio
|
|
|
95
105
|
readonly namespaceBinding: string;
|
|
96
106
|
}
|
|
97
107
|
|
|
98
|
-
type ConversationObjectError =
|
|
108
|
+
type ConversationObjectError<TelemetryError> =
|
|
109
|
+
| CloudflareDurableRuntimeInitializationError
|
|
110
|
+
| CloudflareBindingError
|
|
111
|
+
| TelemetryError;
|
|
99
112
|
|
|
100
|
-
type EndpointServices =
|
|
113
|
+
type EndpointServices =
|
|
114
|
+
| CloudflareDurableRuntimeServices
|
|
115
|
+
| DurableObjectContext
|
|
116
|
+
| CloudflareRuntimeTelemetry;
|
|
101
117
|
|
|
102
118
|
/** Port envelope tags whose owner-side execution durably mutates this Object's lane. */
|
|
103
119
|
const MUTATING_PORT_TAGS: ReadonlySet<string> = new Set([
|
|
@@ -608,6 +624,54 @@ const gateEndpoint: Effect.Effect<void, unknown, EndpointServices> = Effect.gen(
|
|
|
608
624
|
yield* maintenance.ensureAlarm;
|
|
609
625
|
});
|
|
610
626
|
|
|
627
|
+
const NATIVE_ENTRYPOINTS = [
|
|
628
|
+
"submit",
|
|
629
|
+
"await_settlement",
|
|
630
|
+
"observe",
|
|
631
|
+
"abort",
|
|
632
|
+
"resolve_approval",
|
|
633
|
+
"resolve_unknown",
|
|
634
|
+
"explain",
|
|
635
|
+
"verify",
|
|
636
|
+
"retry",
|
|
637
|
+
"obligations",
|
|
638
|
+
"port_call",
|
|
639
|
+
"wake",
|
|
640
|
+
"alarm",
|
|
641
|
+
] as const;
|
|
642
|
+
|
|
643
|
+
type NativeEntrypoint = (typeof NATIVE_ENTRYPOINTS)[number];
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* Owner-side delivery measurement. The exact endpoint Cause is hidden behind a bounded typed
|
|
647
|
+
* marker while the span closes, then restored together with any newly composed real reasons.
|
|
648
|
+
*/
|
|
649
|
+
const observeNativeEntrypoint = <A, E>(
|
|
650
|
+
entrypoint: NativeEntrypoint,
|
|
651
|
+
effect: Effect.Effect<A, E, EndpointServices>,
|
|
652
|
+
): Effect.Effect<A, E, EndpointServices> =>
|
|
653
|
+
Effect.gen(function* () {
|
|
654
|
+
const identity = yield* ConversationObjectIdentity;
|
|
655
|
+
const config = yield* CloudflareDurableRuntimeConfig;
|
|
656
|
+
return yield* withCloudflareNativeSpanFailure(effect, (masked) =>
|
|
657
|
+
masked.pipe(
|
|
658
|
+
Effect.withSpan(`effect_agent.cloudflare.conversation_object.${entrypoint}`, {
|
|
659
|
+
kind: "server",
|
|
660
|
+
attributes: {
|
|
661
|
+
"effect_agent.cloudflare.entrypoint": entrypoint,
|
|
662
|
+
"effect_agent.deployment.id": config.deploymentId,
|
|
663
|
+
conversationId: identity.conversationId,
|
|
664
|
+
producerId: identity.producerId,
|
|
665
|
+
},
|
|
666
|
+
}),
|
|
667
|
+
),
|
|
668
|
+
);
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
const flushNativeEntrypointTelemetry = Effect.flatMap(CloudflareDurableRuntimeConfig, (config) =>
|
|
672
|
+
flushCloudflareRuntimeTelemetry(config.telemetryFlushTimeout),
|
|
673
|
+
);
|
|
674
|
+
|
|
611
675
|
/** The public endpoint surface of one Conversation Object instance. */
|
|
612
676
|
export interface ConversationObjectInstance extends DurableObject {
|
|
613
677
|
submitEncoded(encoded: unknown): Promise<unknown>;
|
|
@@ -631,84 +695,151 @@ export interface ConversationObjectClass {
|
|
|
631
695
|
}
|
|
632
696
|
|
|
633
697
|
/**
|
|
634
|
-
* Build the application's Conversation Object class (export it from the
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
698
|
+
* Build the application's Conversation Object class (export it from the Worker entry).
|
|
699
|
+
* `telemetry` is the host composition boundary: it may require the Object context/namespace and
|
|
700
|
+
* retain a typed acquisition error, while any additional output services remain available to the
|
|
701
|
+
* cached runtime. `TelemetryError` stays the first explicit generic for source compatibility;
|
|
702
|
+
* additional outputs infer from the Layer. Omitting it installs the content-free no-op service.
|
|
703
|
+
* The explicit return type is what makes declaration emit possible: the class body carries a
|
|
704
|
+
* private runtime field, and TS4094 rejects inferring an exported anonymous class type around it.
|
|
638
705
|
*/
|
|
639
|
-
export const makeConversationObjectClass =
|
|
706
|
+
export const makeConversationObjectClass = <
|
|
707
|
+
TelemetryError = never,
|
|
708
|
+
AdditionalTelemetryOutputs = never,
|
|
709
|
+
>(
|
|
640
710
|
options: ConversationObjectOptions,
|
|
711
|
+
telemetry?: Layer.Layer<
|
|
712
|
+
CloudflareRuntimeTelemetry | AdditionalTelemetryOutputs,
|
|
713
|
+
TelemetryError,
|
|
714
|
+
DurableObjectContext | ConversationObjectNamespace
|
|
715
|
+
>,
|
|
641
716
|
): ConversationObjectClass => {
|
|
642
717
|
class ConversationObject extends DurableObject {
|
|
643
|
-
readonly #runtime: ManagedRuntime.ManagedRuntime<
|
|
718
|
+
readonly #runtime: ManagedRuntime.ManagedRuntime<
|
|
719
|
+
EndpointServices,
|
|
720
|
+
ConversationObjectError<TelemetryError>
|
|
721
|
+
>;
|
|
722
|
+
readonly #ctx: DurableObjectState;
|
|
723
|
+
readonly #telemetryFlush: CloudflareTelemetryFlushCoordinator;
|
|
644
724
|
|
|
645
725
|
constructor(ctx: DurableObjectState, env: Cloudflare.Env) {
|
|
646
726
|
super(ctx, env);
|
|
727
|
+
this.#ctx = ctx;
|
|
728
|
+
const platform = Layer.mergeAll(
|
|
729
|
+
DurableObjectContext.layer(ctx, env),
|
|
730
|
+
conversationNamespaceLayer(env, options.namespaceBinding),
|
|
731
|
+
);
|
|
732
|
+
// Host observability is composed at the Worker edge, not hidden in runtime options. Its
|
|
733
|
+
// typed acquisition failure remains in the ManagedRuntime error, while the Object context
|
|
734
|
+
// and namespace are available to Layers that derive exporter configuration from `env`.
|
|
735
|
+
const hostTelemetry = (telemetry ?? CloudflareRuntimeTelemetry.layerNoop).pipe(
|
|
736
|
+
Layer.provideMerge(platform),
|
|
737
|
+
);
|
|
647
738
|
this.#runtime = ManagedRuntime.make(
|
|
648
739
|
CloudflareDurableRuntime.layer(options).pipe(
|
|
649
|
-
Layer
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
conversationNamespaceLayer(env, options.namespaceBinding),
|
|
653
|
-
),
|
|
654
|
-
),
|
|
740
|
+
// Supplying the host Layer outermost makes its Logger/Tracer/Metric runtime
|
|
741
|
+
// configuration observe application Layer acquisition and every native endpoint.
|
|
742
|
+
Layer.provideMerge(hostTelemetry),
|
|
655
743
|
),
|
|
656
744
|
);
|
|
745
|
+
this.#telemetryFlush = makeCloudflareTelemetryFlushCoordinator(
|
|
746
|
+
() => this.#runtime.runPromise(flushNativeEntrypointTelemetry),
|
|
747
|
+
{
|
|
748
|
+
onReservationDropped: () => {
|
|
749
|
+
void this.#runtime.runSyncExit(
|
|
750
|
+
Effect.logWarning(
|
|
751
|
+
"Cloudflare telemetry delivery coalesced at the batch reservation limit",
|
|
752
|
+
).pipe(
|
|
753
|
+
Effect.annotateLogs({
|
|
754
|
+
"effect_agent.cloudflare.telemetry.failure_kind": "reservation_limit",
|
|
755
|
+
}),
|
|
756
|
+
),
|
|
757
|
+
);
|
|
758
|
+
},
|
|
759
|
+
},
|
|
760
|
+
);
|
|
657
761
|
// The constructor gate: local-only checks; never the recovery pass (deadlock argument,
|
|
658
762
|
// plan §1.4). A failure here fails every delivery with the typed construction error.
|
|
659
763
|
ctx.blockConcurrencyWhile(() => this.#runtime.runPromise(gateEndpoint));
|
|
660
764
|
}
|
|
661
765
|
|
|
766
|
+
#runNative<A, E>(
|
|
767
|
+
entrypoint: NativeEntrypoint,
|
|
768
|
+
effect: Effect.Effect<A, E, EndpointServices>,
|
|
769
|
+
): Promise<A> {
|
|
770
|
+
const delivery = this.#runtime.runPromise(observeNativeEntrypoint(entrypoint, effect));
|
|
771
|
+
// Reserve synchronously with the current native delivery, but do not await export from the
|
|
772
|
+
// RPC/alarm Promise. Each pending/trailing/queued batch waits for its assigned deliveries to
|
|
773
|
+
// settle and only its first owner registers the shared background Promise. Even an
|
|
774
|
+
// uninterruptible exporter therefore cannot delay a caller, suppress alarm retry, accumulate
|
|
775
|
+
// concurrent exporter work, an unbounded waitUntil registration queue, or unbounded retained
|
|
776
|
+
// delivery Promises. Excess arrivals are diagnosed and lossy-coalesced at the batch cap.
|
|
777
|
+
// Registration failure and every asynchronous flush failure remain isolated from delivery.
|
|
778
|
+
return registerCloudflareTelemetryAfterNativeSettlement(
|
|
779
|
+
(background) => this.#ctx.waitUntil(background),
|
|
780
|
+
delivery,
|
|
781
|
+
this.#telemetryFlush.reserve,
|
|
782
|
+
(cause) => {
|
|
783
|
+
// Native entrypoints run only after blockConcurrencyWhile has built the cached runtime.
|
|
784
|
+
// Effect Logger invocation is synchronous; runSyncExit captures a broken logger without
|
|
785
|
+
// starting an unscoped fiber or changing the delivery Promise. The exact platform value
|
|
786
|
+
// stays confined to this registration callback; the automatic Logger diagnostic is
|
|
787
|
+
// deliberately content-free.
|
|
788
|
+
void this.#runtime.runSyncExit(logCloudflareWaitUntilRegistrationFailure(cause));
|
|
789
|
+
},
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
|
|
662
793
|
async submitEncoded(encoded: unknown): Promise<unknown> {
|
|
663
|
-
return this.#
|
|
794
|
+
return this.#runNative("submit", submitEndpoint(encoded));
|
|
664
795
|
}
|
|
665
796
|
|
|
666
797
|
async awaitSettlementEncoded(encoded: unknown): Promise<unknown> {
|
|
667
|
-
return this.#
|
|
798
|
+
return this.#runNative("await_settlement", awaitSettlementEndpoint(encoded));
|
|
668
799
|
}
|
|
669
800
|
|
|
670
801
|
async observePage(encoded: unknown): Promise<unknown> {
|
|
671
|
-
return this.#
|
|
802
|
+
return this.#runNative("observe", observePageEndpoint(encoded));
|
|
672
803
|
}
|
|
673
804
|
|
|
674
805
|
async abortEncoded(encoded: unknown): Promise<unknown> {
|
|
675
|
-
return this.#
|
|
806
|
+
return this.#runNative("abort", abortEndpoint(encoded));
|
|
676
807
|
}
|
|
677
808
|
|
|
678
809
|
async resolveApprovalEncoded(encoded: unknown): Promise<unknown> {
|
|
679
|
-
return this.#
|
|
810
|
+
return this.#runNative("resolve_approval", resolveApprovalEndpoint(encoded));
|
|
680
811
|
}
|
|
681
812
|
|
|
682
813
|
async resolveUnknownEncoded(encoded: unknown): Promise<unknown> {
|
|
683
|
-
return this.#
|
|
814
|
+
return this.#runNative("resolve_unknown", resolveUnknownEndpoint(encoded));
|
|
684
815
|
}
|
|
685
816
|
|
|
686
817
|
async explainEncoded(encoded: unknown): Promise<unknown> {
|
|
687
|
-
return this.#
|
|
818
|
+
return this.#runNative("explain", explainEndpoint(encoded));
|
|
688
819
|
}
|
|
689
820
|
|
|
690
821
|
async verifyEncoded(encoded: unknown): Promise<unknown> {
|
|
691
|
-
return this.#
|
|
822
|
+
return this.#runNative("verify", verifyEndpoint(encoded));
|
|
692
823
|
}
|
|
693
824
|
|
|
694
825
|
async retryEncoded(encoded: unknown): Promise<unknown> {
|
|
695
|
-
return this.#
|
|
826
|
+
return this.#runNative("retry", retryEndpoint(encoded));
|
|
696
827
|
}
|
|
697
828
|
|
|
698
829
|
async obligationsEncoded(encoded: unknown): Promise<unknown> {
|
|
699
|
-
return this.#
|
|
830
|
+
return this.#runNative("obligations", obligationsEndpoint(encoded));
|
|
700
831
|
}
|
|
701
832
|
|
|
702
833
|
async portCall(encoded: unknown): Promise<unknown> {
|
|
703
|
-
return this.#
|
|
834
|
+
return this.#runNative("port_call", portCallEndpoint(encoded));
|
|
704
835
|
}
|
|
705
836
|
|
|
706
837
|
async wake(): Promise<void> {
|
|
707
|
-
await this.#
|
|
838
|
+
await this.#runNative("wake", wakeEndpoint);
|
|
708
839
|
}
|
|
709
840
|
|
|
710
841
|
override async alarm(): Promise<void> {
|
|
711
|
-
await this.#
|
|
842
|
+
await this.#runNative("alarm", alarmEndpoint);
|
|
712
843
|
}
|
|
713
844
|
}
|
|
714
845
|
|
package/src/index.ts
CHANGED
|
@@ -17,6 +17,8 @@ export * from "./config.ts";
|
|
|
17
17
|
export * from "./alarm.ts";
|
|
18
18
|
export * from "./wake-scheduler.ts";
|
|
19
19
|
export * from "./transport.ts";
|
|
20
|
+
export * from "./telemetry.ts";
|
|
20
21
|
export * from "./layers.ts";
|
|
21
22
|
export * from "./conversation-object.ts";
|
|
22
23
|
export * from "./client.ts";
|
|
24
|
+
export * from "./code-mode-executor.ts";
|
package/src/layers.ts
CHANGED
|
@@ -31,8 +31,8 @@ import { Context, Duration, Effect, Layer, Schema } from "effect";
|
|
|
31
31
|
import { ConversationMaintenance, DurableAlarmService } from "./alarm.ts";
|
|
32
32
|
import {
|
|
33
33
|
ConversationObjectIdentity,
|
|
34
|
-
ConversationObjectNamespace,
|
|
35
34
|
DurableObjectContext,
|
|
35
|
+
type ConversationObjectNamespace,
|
|
36
36
|
} from "./bindings.ts";
|
|
37
37
|
import {
|
|
38
38
|
CLOUDFLARE_RUNTIME_DEFAULTS,
|
|
@@ -69,6 +69,11 @@ export interface CloudflareDurableRuntimeOptions {
|
|
|
69
69
|
readonly abortPollInterval?: number | undefined;
|
|
70
70
|
/** Milliseconds; default 25. */
|
|
71
71
|
readonly observationPollInterval?: number | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* Milliseconds; default 2000. Cooperative budget for the background exporter flush registered
|
|
74
|
+
* after each native RPC, wake, or alarm span. Delivery never awaits the flush.
|
|
75
|
+
*/
|
|
76
|
+
readonly telemetryFlushTimeout?: number | undefined;
|
|
72
77
|
/** Bytes; default just under the 2 MB platform value limit. */
|
|
73
78
|
readonly maxStoredValueBytes?: number | undefined;
|
|
74
79
|
/** Default false. */
|
|
@@ -97,16 +102,35 @@ export interface CloudflareDurableRuntimeOptions {
|
|
|
97
102
|
readonly toolReconciler?: Layer.Layer<ToolReconciler> | undefined;
|
|
98
103
|
/**
|
|
99
104
|
* Registered worker Bindings resolved at durable claim time (S2, spec/subagents.md §11):
|
|
100
|
-
* build each with `DurableWorkerBinding.make(binding, digests)`. An Effect form is
|
|
101
|
-
* because
|
|
102
|
-
*
|
|
105
|
+
* build each with `DurableWorkerBinding.make(binding, digests)`. An Effect or callback form is
|
|
106
|
+
* accepted because capture can be effectful. The callback receives the live Object context and
|
|
107
|
+
* derived identities and is evaluated once per incarnation during Layer construction. Defaults
|
|
108
|
+
* to the empty registration (every resolved claim fails closed).
|
|
103
109
|
*/
|
|
104
|
-
readonly bindings?:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
readonly bindings?: CloudflareBindingSource | undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Per-incarnation host values available while registered worker Bindings are captured. */
|
|
114
|
+
export interface CloudflareBindingSourceContext {
|
|
115
|
+
readonly ctx: DurableObjectState;
|
|
116
|
+
readonly env: unknown;
|
|
117
|
+
readonly conversationId: ConversationId;
|
|
118
|
+
readonly producerId: ProducerId;
|
|
108
119
|
}
|
|
109
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Registered worker Bindings, or a closed Effect/callback that captures them once for each
|
|
123
|
+
* Durable Object incarnation. Callback Effects cannot require services or fail typed.
|
|
124
|
+
*/
|
|
125
|
+
export type CloudflareBindingSource =
|
|
126
|
+
| ReadonlyArray<ResolvedBinding>
|
|
127
|
+
| Effect.Effect<ReadonlyArray<ResolvedBinding>, never, never>
|
|
128
|
+
| ((
|
|
129
|
+
context: CloudflareBindingSourceContext,
|
|
130
|
+
) =>
|
|
131
|
+
| ReadonlyArray<ResolvedBinding>
|
|
132
|
+
| Effect.Effect<ReadonlyArray<ResolvedBinding>, never, never>);
|
|
133
|
+
|
|
110
134
|
/** Every construction failure of the assembled Cloudflare durable runtime stack. */
|
|
111
135
|
export type CloudflareDurableRuntimeInitializationError =
|
|
112
136
|
| CloudflarePlatformConfigError
|
|
@@ -161,6 +185,8 @@ const configFromOptions = (
|
|
|
161
185
|
abortPollInterval: options.abortPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.abortPollInterval,
|
|
162
186
|
observationPollInterval:
|
|
163
187
|
options.observationPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.observationPollInterval,
|
|
188
|
+
telemetryFlushTimeout:
|
|
189
|
+
options.telemetryFlushTimeout ?? CLOUDFLARE_RUNTIME_DEFAULTS.telemetryFlushTimeout,
|
|
164
190
|
maxStoredValueBytes:
|
|
165
191
|
options.maxStoredValueBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxStoredValueBytes,
|
|
166
192
|
verifyOnOpen: options.verifyOnOpen ?? CLOUDFLARE_RUNTIME_DEFAULTS.verifyOnOpen,
|
|
@@ -208,13 +234,19 @@ const conversationIdFromState = (
|
|
|
208
234
|
);
|
|
209
235
|
|
|
210
236
|
const resolveBindings = (
|
|
211
|
-
|
|
237
|
+
source: CloudflareDurableRuntimeOptions["bindings"],
|
|
238
|
+
context: CloudflareBindingSourceContext,
|
|
212
239
|
): Effect.Effect<ReadonlyArray<ResolvedBinding>> =>
|
|
213
|
-
|
|
240
|
+
source === undefined
|
|
214
241
|
? Effect.succeed([])
|
|
215
|
-
: Effect.isEffect(
|
|
216
|
-
?
|
|
217
|
-
:
|
|
242
|
+
: Effect.isEffect(source)
|
|
243
|
+
? source
|
|
244
|
+
: typeof source === "function"
|
|
245
|
+
? Effect.suspend(() => {
|
|
246
|
+
const bindings = source(context);
|
|
247
|
+
return Effect.isEffect(bindings) ? bindings : Effect.succeed(bindings);
|
|
248
|
+
})
|
|
249
|
+
: Effect.succeed(source);
|
|
218
250
|
|
|
219
251
|
/**
|
|
220
252
|
* The DC Layer assembly (deployment §12: a Layer-assembly library, not an app entrypoint;
|
|
@@ -229,9 +261,9 @@ const resolveBindings = (
|
|
|
229
261
|
* Storage compatibility is verified during construction: an incompatible database fails the
|
|
230
262
|
* Layer typed (`DoStorageCompatibilityError`) before anything is mutated (DEPLOY-008).
|
|
231
263
|
*
|
|
232
|
-
* Requires
|
|
233
|
-
*
|
|
234
|
-
* (DEPLOY-010).
|
|
264
|
+
* Requires the two binding services (`DurableObjectContext`, `ConversationObjectNamespace`).
|
|
265
|
+
* Host observability belongs to the Worker composition edge because native entrypoint lifecycle
|
|
266
|
+
* instrumentation, rather than this durable runtime assembly, consumes it (DEPLOY-010).
|
|
235
267
|
*/
|
|
236
268
|
export class CloudflareDurableRuntime {
|
|
237
269
|
static layer(
|
|
@@ -243,7 +275,7 @@ export class CloudflareDurableRuntime {
|
|
|
243
275
|
> {
|
|
244
276
|
return Layer.unwrap(
|
|
245
277
|
Effect.gen(function* () {
|
|
246
|
-
const { ctx } = yield* DurableObjectContext;
|
|
278
|
+
const { ctx, env } = yield* DurableObjectContext;
|
|
247
279
|
const config = yield* configFromOptions(options);
|
|
248
280
|
const conversationId = yield* conversationIdFromState(ctx);
|
|
249
281
|
const producerId = yield* decodeProducerId(
|
|
@@ -317,7 +349,10 @@ export class CloudflareDurableRuntime {
|
|
|
317
349
|
: Layer.succeed(DurableRuntimeFailpoint)({ hit: options.runtimeFailpoint(ctx) });
|
|
318
350
|
const reconcilerLayer = options.toolReconciler ?? ToolReconciler.uncertain;
|
|
319
351
|
const bindingResolverLayer = Layer.effect(AgentBindingResolver)(
|
|
320
|
-
Effect.map(
|
|
352
|
+
Effect.map(
|
|
353
|
+
resolveBindings(options.bindings, { ctx, env, conversationId, producerId }),
|
|
354
|
+
(bindings) => AgentBindingResolver.fromBindings(bindings),
|
|
355
|
+
),
|
|
321
356
|
);
|
|
322
357
|
|
|
323
358
|
const base = Layer.mergeAll(
|
|
@@ -337,11 +372,13 @@ export class CloudflareDurableRuntime {
|
|
|
337
372
|
Layer.provideMerge(base),
|
|
338
373
|
);
|
|
339
374
|
|
|
340
|
-
|
|
375
|
+
const application = Layer.mergeAll(
|
|
341
376
|
runtimeStack,
|
|
342
377
|
ConversationMaintenance.layer.pipe(Layer.provide(runtimeStack)),
|
|
343
378
|
portsEndpointLayer,
|
|
344
379
|
);
|
|
380
|
+
|
|
381
|
+
return application;
|
|
345
382
|
}),
|
|
346
383
|
);
|
|
347
384
|
}
|