@effect-agent/platform-cloudflare 0.1.0-beta.38 → 0.1.0-beta.40
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/bindings-BrVEOkfe.d.mts +102 -0
- package/dist/browser-quick-action.d.mts +18 -1
- package/dist/browser-quick-action.mjs +14 -1
- package/dist/browser-quick-action.mjs.map +1 -1
- package/dist/browser-rest-capture.d.mts +17 -2
- package/dist/browser-rest-capture.mjs +12 -1
- package/dist/browser-rest-capture.mjs.map +1 -1
- package/dist/browser-rest-crawl.mjs +2 -2
- package/dist/browser-rest-crawl.mjs.map +1 -1
- package/dist/index.d.mts +245 -237
- package/dist/index.mjs +168 -164
- package/dist/index.mjs.map +1 -1
- package/dist/interactive-browser.d.mts +160 -2
- package/dist/interactive-browser.mjs +1166 -2
- package/dist/interactive-browser.mjs.map +1 -0
- package/dist/{scheduling-B-OFqoS9.mjs → prepared-admission-BKp_Upw2.mjs} +134 -433
- package/dist/prepared-admission-BKp_Upw2.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/scheduling.d.mts +47 -2
- package/dist/scheduling.mjs +339 -1
- package/dist/scheduling.mjs.map +1 -0
- package/dist/subscriptions.d.mts +52 -0
- package/dist/subscriptions.mjs +346 -0
- package/dist/subscriptions.mjs.map +1 -0
- package/package.json +20 -13
- package/src/alarm.ts +264 -265
- package/src/bindings.ts +34 -30
- package/src/browser-quick-action.ts +31 -0
- package/src/browser-rest-capture.ts +27 -0
- package/src/client.ts +111 -105
- package/src/code-mode-executor.ts +19 -0
- package/src/config.ts +7 -7
- package/src/index.ts +10 -11
- package/src/interactive-browser.ts +29 -1
- package/src/layers.ts +178 -257
- package/src/prepared-admission.ts +90 -0
- package/src/scheduling.ts +19 -55
- package/src/subscriptions.ts +661 -0
- package/src/{conversation-object.ts → thread-object.ts} +167 -136
- package/src/transport.ts +15 -15
- package/src/wake-scheduler.ts +17 -22
- package/dist/interactive-browser-BRo-Bfvb.d.mts +0 -144
- package/dist/interactive-browser-Cy5q-ldl.mjs +0 -1154
- package/dist/interactive-browser-Cy5q-ldl.mjs.map +0 -1
- package/dist/scheduling-B-OFqoS9.mjs.map +0 -1
- package/dist/scheduling-BJs_kHTx.d.mts +0 -142
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { $ as CloudflarePlatformConfigError, A as decodeUnknownResolutionCommand, B as DurableAlarmError, C as decodeApprovalDecisionCommand, D as decodeObservePageRequest, E as decodeHostResponse, F as encodeHostResponse, G as safeCauseDiagnostic, H as MaintenancePassReport, I as encodeObservePageRequest, J as CLOUDFLARE_DATABASE_CAP_BYTES, K as safeCauseMessage, L as encodeReceipt, M as encodeApprovalDecisionCommand, N as encodeAwaitProgressRequest, O as decodeReceipt, P as encodeCancelProgressRequest, Q as CloudflareDurableRuntimeConfigValue, R as encodeSubmitRequest, S as decodeAbortCommand, T as decodeCancelProgressRequest, U as ThreadMaintenance, V as DurableAlarmService, W as ThreadMaintenanceFailpoint, X as CloudflareAdmissionLimitsValue, Y as CLOUDFLARE_RUNTIME_DEFAULTS, Z as CloudflareDurableRuntimeConfig, _ as SubmitRequest, a as AwaitProgressRequest, at as threadNamespaceFromEnv, b as UnknownResolutionRecorded, c as HostFailed, d as HostResponse, et as DEFAULT_MAX_DATABASE_BYTES, f as ObservePageRequest, g as SettlementReached, h as ProgressObserved, i as ApprovalRecorded, it as ThreadObjectNamespace, j as encodeAbortCommand, k as decodeSubmitRequest, l as HostFailure, m as ProgressCancelled, n as cloudflareScheduledInputAdmissionLayer, nt as DurableObjectContext, o as CancelProgressRequest, ot as threadNamespaceLayer, p as ObservedPage, q as AdmissionLimitExceeded, r as AbortRecorded, rt as ThreadObjectIdentity, s as CloudflareThreadClient, t as cloudflarePreparedInputAdmissionLayer, tt as CloudflareBindingError, u as HostProtocolError, v as SubmitSucceeded, w as decodeAwaitProgressRequest, x as boundHostDiagnostic, y as ThreadClientError, z as encodeUnknownResolutionCommand } from "./prepared-admission-BKp_Upw2.mjs";
|
|
3
|
+
import { CloudflareSchedulingClient, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerProtocolError, makeScheduleOwnerObjectClass } from "./scheduling.mjs";
|
|
4
|
+
import { CloudflareSubscriptionConfigError, CloudflareSubscriptionsClient, SubscriptionAlarmProtocolError, SubscriptionPartitionIdentity, SubscriptionPartitionNamespace, SubscriptionPartitionProtocolError, makeSubscriptionPartitionObjectClass, sourcePartitionName, validateCloudflareSubscriptionLimits } from "./subscriptions.mjs";
|
|
5
|
+
import { CloudflareBrowser } from "./browser-quick-action.mjs";
|
|
6
6
|
import { Clock, Context, Deferred, Duration, Effect, Exit, Fiber, Layer, Option, PubSub, Queue, Ref, Schema, Stream } from "effect";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { CurrentToolFailureObserver, RunContextPreparationPassthrough, toolFailureObserverLayer } from "@effect-agent/engine";
|
|
7
|
+
import { ThreadPortTransport, decodePortRequest, encodePortResponse, executePortRequest, portTransportFailure, routedSubmissionLedgerLayer, routedThreadStoreLayer, storageConfigLayer, storageFailpointLayer, submissionLedgerLayer, threadStoreLayer } from "@effect-agent/storage-cloudflare";
|
|
8
|
+
import { AppendConflict, DigestError, DurableAgentRuntime, DurableRuntimeConfig, DurableRuntimeFailpoint, DurableRuntimeFailpointError, FenceRejected, IntegrityReport, LedgerError, ObligationReport, ObligationThresholds, OperationAuthorizationRequest, OperationAuthorizer, OperationDenied, OwnershipLost, PersistedJson, ProducerId, RecoveryExplanation, RecoveryReport, RetryCommand, RetryRefused, RunJournalError, SettlementConflict, SubmissionLedger, SubmissionLookupByKey, ThreadNotMaterialized, ThreadRead, ThreadStore, ThreadStoreError, ToolReconciler, WakeScheduler, compileRegistrations, makeWakeSubscriptionHub, operationAuthorizerLayer } from "@effect-agent/thread";
|
|
9
|
+
import { SubmissionId, ThreadId } from "@effect-agent/core";
|
|
10
|
+
import { CurrentToolFailureObserver, RunContextPreparationPassthrough, RunToolAuthorization, toolFailureObserverLayer } from "@effect-agent/engine";
|
|
11
11
|
import { BrowserCrypto } from "@effect/platform-browser";
|
|
12
12
|
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
13
13
|
import { DurableObject, DurableObjectState, WorkerEnvironment } from "effect-cf";
|
|
@@ -23,7 +23,7 @@ import { RpcTarget } from "cloudflare:workers";
|
|
|
23
23
|
const WAKE_BUFFER_CAPACITY = 1024;
|
|
24
24
|
/** A remote wake stub call failed; always swallowed and logged (hints are droppable). */
|
|
25
25
|
var RemoteWakeDropped = class extends Schema.TaggedError()("RemoteWakeDropped", {
|
|
26
|
-
|
|
26
|
+
threadId: Schema.String,
|
|
27
27
|
message: Schema.String,
|
|
28
28
|
cause: Schema.optionalKey(Schema.Defect())
|
|
29
29
|
}) {};
|
|
@@ -41,22 +41,22 @@ var RemoteWakeDropped = class extends Schema.TaggedError()("RemoteWakeDropped",
|
|
|
41
41
|
*/
|
|
42
42
|
const cloudflareWakeSchedulerLayer = Layer.effect(WakeScheduler)(Effect.gen(function* () {
|
|
43
43
|
const alarm = yield* DurableAlarmService;
|
|
44
|
-
const identity = yield*
|
|
45
|
-
const { namespace } = yield*
|
|
44
|
+
const identity = yield* ThreadObjectIdentity;
|
|
45
|
+
const { namespace } = yield* ThreadObjectNamespace;
|
|
46
46
|
const hints = yield* PubSub.sliding(WAKE_BUFFER_CAPACITY);
|
|
47
47
|
const progress = yield* makeWakeSubscriptionHub;
|
|
48
48
|
yield* Effect.addFinalizer(() => PubSub.shutdown(hints));
|
|
49
|
-
const notifyLocal = (
|
|
50
|
-
const notifyRemote = (
|
|
51
|
-
try: () => namespace.get(namespace.idFromName(
|
|
49
|
+
const notifyLocal = (threadId) => progress.notify(threadId).pipe(Effect.andThen(PubSub.publish(hints, threadId)), Effect.andThen(alarm.scheduleNow), Effect.catch((error) => Effect.logWarning("CloudflareWakeScheduler: local alarm wake failed", error)), Effect.asVoid);
|
|
50
|
+
const notifyRemote = (threadId) => Effect.tryPromise({
|
|
51
|
+
try: () => namespace.get(namespace.idFromName(threadId)).wake(),
|
|
52
52
|
catch: (cause) => RemoteWakeDropped.make({
|
|
53
|
-
|
|
53
|
+
threadId,
|
|
54
54
|
message: safeCauseMessage(cause, "The remote wake failed without a diagnostic"),
|
|
55
55
|
cause
|
|
56
56
|
})
|
|
57
|
-
}).pipe(Effect.catch((error) => Effect.logWarning(`CloudflareWakeScheduler: remote wake of ${
|
|
57
|
+
}).pipe(Effect.catch((error) => Effect.logWarning(`CloudflareWakeScheduler: remote wake of ${threadId} dropped`, error)), Effect.asVoid);
|
|
58
58
|
return WakeScheduler.of({
|
|
59
|
-
notify: (
|
|
59
|
+
notify: (threadId) => threadId === identity.threadId ? notifyLocal(threadId) : notifyRemote(threadId),
|
|
60
60
|
subscribe: progress.subscribe,
|
|
61
61
|
wakes: Stream.fromPubSub(hints)
|
|
62
62
|
});
|
|
@@ -129,9 +129,9 @@ var ProgressWaitRegistry = class ProgressWaitRegistry extends Context.Service()(
|
|
|
129
129
|
//#endregion
|
|
130
130
|
//#region src/transport.ts
|
|
131
131
|
/**
|
|
132
|
-
* `
|
|
133
|
-
* `portCall(envelope)` on the stub of the Object that owns the addressed
|
|
134
|
-
* (`namespace.idFromName(
|
|
132
|
+
* `ThreadPortTransport` over native Durable Object JS RPC (decision D-P6-3): one
|
|
133
|
+
* `portCall(envelope)` on the stub of the Object that owns the addressed Thread
|
|
134
|
+
* (`namespace.idFromName(threadId)` — the identity rule, plan §1.2). The envelopes are
|
|
135
135
|
* already Schema-encoded JSON, so the RPC boundary carries only structured-cloneable values;
|
|
136
136
|
* the protocol module stays transport-agnostic and fetch-with-JSON remains the documented
|
|
137
137
|
* fallback carrier.
|
|
@@ -141,12 +141,12 @@ var ProgressWaitRegistry = class ProgressWaitRegistry extends Context.Service()(
|
|
|
141
141
|
* when present) and NEVER as a fabricated answer: on `resolveAdmission` the routing layer
|
|
142
142
|
* turns exactly this error into `AdmissionIndeterminate` (SUB-031).
|
|
143
143
|
*/
|
|
144
|
-
const
|
|
145
|
-
const { namespace } = yield*
|
|
146
|
-
return
|
|
147
|
-
try: () => namespace.get(namespace.idFromName(
|
|
148
|
-
catch: (cause) => portTransportFailure(
|
|
149
|
-
}).pipe(Effect.withSpan("CloudflarePortTransport.call", { attributes: {
|
|
144
|
+
const threadPortTransportLayer = Layer.effect(ThreadPortTransport)(Effect.gen(function* () {
|
|
145
|
+
const { namespace } = yield* ThreadObjectNamespace;
|
|
146
|
+
return ThreadPortTransport.of({ call: (threadId, request) => Effect.tryPromise({
|
|
147
|
+
try: () => namespace.get(namespace.idFromName(threadId)).portCall(request),
|
|
148
|
+
catch: (cause) => portTransportFailure(threadId, cause)
|
|
149
|
+
}).pipe(Effect.withSpan("CloudflarePortTransport.call", { attributes: { threadId } })) });
|
|
150
150
|
}));
|
|
151
151
|
//#endregion
|
|
152
152
|
//#region src/layers.ts
|
|
@@ -156,9 +156,9 @@ const conversationPortTransportLayer = Layer.effect(ConversationPortTransport)(E
|
|
|
156
156
|
* request cannot bounce between Objects — and returns the typed response for the endpoint to
|
|
157
157
|
* encode.
|
|
158
158
|
*/
|
|
159
|
-
var
|
|
159
|
+
var ThreadObjectPorts = class extends Context.Service()("@effect-agent/platform-cloudflare/ThreadObjectPorts") {};
|
|
160
160
|
const decodeConfigValue = Schema.decodeUnknownEffect(CloudflareDurableRuntimeConfigValue);
|
|
161
|
-
const
|
|
161
|
+
const decodeThreadId = Schema.decodeUnknownEffect(ThreadId);
|
|
162
162
|
const decodeProducerId = Schema.decodeUnknownEffect(ProducerId);
|
|
163
163
|
const configFromOptions = (options) => decodeConfigValue({
|
|
164
164
|
deploymentId: options.deploymentId,
|
|
@@ -183,101 +183,94 @@ const configFromOptions = (options) => decodeConfigValue({
|
|
|
183
183
|
cause: error
|
|
184
184
|
})));
|
|
185
185
|
/**
|
|
186
|
-
* The
|
|
187
|
-
* Objects are addressed exclusively by `idFromName(
|
|
188
|
-
*
|
|
186
|
+
* The Thread this Object owns, from the Object identity rule (plan §1.2): Thread
|
|
187
|
+
* Objects are addressed exclusively by `idFromName(threadId)`, so `ctx.id.name` IS the
|
|
188
|
+
* Thread ID. An unnamed Object (from `newUniqueId`) is a deployment error, not a lane.
|
|
189
189
|
*/
|
|
190
|
-
const
|
|
191
|
-
message: `The Durable Object name is not a valid
|
|
190
|
+
const threadIdFromState = (ctx) => ctx.id.name === void 0 ? Effect.fail(CloudflarePlatformConfigError.make({ message: "This Durable Object was not created via idFromName(threadId); Thread Objects must be addressed by their Thread identity (plan §1.2)." })) : decodeThreadId(ctx.id.name).pipe(Effect.mapError((error) => CloudflarePlatformConfigError.make({
|
|
191
|
+
message: `The Durable Object name is not a valid ThreadId: ${error.message}`,
|
|
192
192
|
cause: error
|
|
193
193
|
})));
|
|
194
|
-
const resolveBindings = (source, context) => source === void 0 ? Effect.succeed([]) : Effect.suspend(() => source(context));
|
|
195
|
-
const resolveRunContext = (source, context) => typeof source === "function" ? source(context) : source;
|
|
196
194
|
/**
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* `@effect/sql-sqlite-do` for BOTH the Conversation Log and the Submission Ledger (so claims
|
|
201
|
-
* fence the same producer epochs — ADR-0011 D7 transposed), wraps the local port facets with
|
|
202
|
-
* the WP2 cross-Object routing decorators over the Durable Object RPC transport, wires the
|
|
203
|
-
* alarm-backed wake scheduler and the maintenance pass, defaults reconciliation to the
|
|
204
|
-
* fail-closed `ToolReconciler.uncertain`, and provides a ready `DurableAgentRuntime` on top.
|
|
205
|
-
*
|
|
206
|
-
* Storage compatibility is verified during construction: an incompatible database fails the
|
|
207
|
-
* Layer typed (`DoStorageCompatibilityError`) before anything is mutated (DEPLOY-008).
|
|
208
|
-
*
|
|
209
|
-
* Requires only the two binding services (`DurableObjectContext`,
|
|
210
|
-
* `ConversationObjectNamespace`) — platform values enter exclusively through Layers
|
|
211
|
-
* (DEPLOY-010).
|
|
195
|
+
* Validate deployment settings and derive services before building application dependencies.
|
|
196
|
+
* The native class factory builds this Layer inside its constructor gate. Custom Effect hosts
|
|
197
|
+
* can provide it around the complete application Layer with the native context already supplied.
|
|
212
198
|
*/
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}), (bindings) => AgentBindingResolver.fromBindings(bindings)));
|
|
267
|
-
const runContextLayer = options.runContext === void 0 ? RunContextPreparationPassthrough : resolveRunContext(options.runContext, {
|
|
268
|
-
ctx,
|
|
269
|
-
env,
|
|
270
|
-
conversationId,
|
|
271
|
-
producerId
|
|
272
|
-
}).pipe(Layer.provide(BrowserCrypto.layer));
|
|
273
|
-
const base = Layer.mergeAll(identityLayer, cloudflareConfigLayer, DurableAlarmService.layer, maintenanceFailpointLayer, ProgressWaitRegistry.layer);
|
|
274
|
-
const runtimeStack = DurableAgentRuntime.layerWithContext.pipe(Layer.provideMerge(routedPorts), Layer.provideMerge(cloudflareWakeSchedulerLayer), Layer.provideMerge(runtimeConfigLayer), Layer.provideMerge(bindingResolverLayer), Layer.provide(Layer.mergeAll(runtimeFailpointLayer, reconcilerLayer, authorizerLayer, observerLayer, runContextLayer, BrowserCrypto.layer)), Layer.provideMerge(base));
|
|
275
|
-
return Layer.mergeAll(runtimeStack, ConversationMaintenance.layer.pipe(Layer.provide(runtimeStack)), portsEndpointLayer);
|
|
276
|
-
}));
|
|
277
|
-
}
|
|
278
|
-
};
|
|
199
|
+
const layerConfig = (options) => Layer.unwrap(Effect.gen(function* () {
|
|
200
|
+
const { ctx } = yield* DurableObjectContext;
|
|
201
|
+
const config = yield* configFromOptions(options);
|
|
202
|
+
const threadId = yield* threadIdFromState(ctx);
|
|
203
|
+
const producerId = yield* decodeProducerId(`${config.producerPrefix}:${threadId}`).pipe(Effect.mapError((error) => CloudflarePlatformConfigError.make({
|
|
204
|
+
message: `The minted producer identity is invalid: ${error.message}`,
|
|
205
|
+
cause: error
|
|
206
|
+
})));
|
|
207
|
+
return Layer.mergeAll(Layer.succeed(CloudflareDurableRuntimeConfig, config), Layer.succeed(ThreadObjectIdentity, {
|
|
208
|
+
threadId,
|
|
209
|
+
producerId
|
|
210
|
+
}), DurableRuntimeConfig.layer({
|
|
211
|
+
deploymentId: config.deploymentId,
|
|
212
|
+
producerId,
|
|
213
|
+
settlementPollInterval: Duration.millis(config.settlementPollInterval),
|
|
214
|
+
leaseRenewalInterval: Duration.millis(config.leaseRenewalInterval),
|
|
215
|
+
abortPollInterval: Duration.millis(config.abortPollInterval),
|
|
216
|
+
...options.estimateCostMicrousd === void 0 ? {} : { estimateCostMicrousd: options.estimateCostMicrousd }
|
|
217
|
+
}), BrowserCrypto.layer, storageFailpointLayer({
|
|
218
|
+
storage: ctx.storage,
|
|
219
|
+
failpoint: options.storageFailpoint?.(ctx)
|
|
220
|
+
}), options.runtimeFailpoint === void 0 ? DurableRuntimeFailpoint.layer : Layer.succeed(DurableRuntimeFailpoint, { hit: options.runtimeFailpoint(ctx) }), options.maintenanceFailpoint === void 0 ? ThreadMaintenanceFailpoint.layer : Layer.succeed(ThreadMaintenanceFailpoint, { hit: options.maintenanceFailpoint(ctx) }), options.toolReconciler ?? ToolReconciler.uncertain, options.operationAuthorizer === void 0 ? Layer.empty : operationAuthorizerLayer(options.operationAuthorizer), options.toolFailureObserver === void 0 ? Layer.succeed(CurrentToolFailureObserver, void 0) : toolFailureObserverLayer(options.toolFailureObserver), RunContextPreparationPassthrough, RunToolAuthorization.allowAll);
|
|
221
|
+
}));
|
|
222
|
+
/**
|
|
223
|
+
* Register typed Agents and version declarations. Hashing and dependency capture happen in
|
|
224
|
+
* this Layer's Scope, after application Layers have been provided. Every Agent's instruction,
|
|
225
|
+
* Tool, Schema, and model requirements remain visible until satisfied by Layer composition.
|
|
226
|
+
* Use Layer.unwrap for registration values that need effectful application setup.
|
|
227
|
+
*/
|
|
228
|
+
const layer = (registrations) => Layer.unwrap(Effect.map(compileRegistrations(registrations), layerFromBindings));
|
|
229
|
+
/** Internal assembly shared by registration compilation and low-level adapter fixtures. */
|
|
230
|
+
const layerFromBindings = (bindings) => Layer.unwrap(Effect.gen(function* () {
|
|
231
|
+
const { ctx } = yield* DurableObjectContext;
|
|
232
|
+
const config = yield* CloudflareDurableRuntimeConfig;
|
|
233
|
+
const { threadId } = yield* ThreadObjectIdentity;
|
|
234
|
+
const storageOptions = {
|
|
235
|
+
storage: ctx.storage,
|
|
236
|
+
observationPollInterval: config.observationPollInterval,
|
|
237
|
+
ownershipLeaseDuration: config.ownershipLeaseDuration,
|
|
238
|
+
maxStoredValueBytes: config.maxStoredValueBytes,
|
|
239
|
+
verifyOnOpen: config.verifyOnOpen
|
|
240
|
+
};
|
|
241
|
+
const infrastructure = Layer.mergeAll(storageConfigLayer(storageOptions), SqliteClient.layer({ storage: ctx.storage }));
|
|
242
|
+
const localPorts = Layer.mergeAll(threadStoreLayer, submissionLedgerLayer).pipe(Layer.provide(infrastructure));
|
|
243
|
+
const portsEndpointLayer = Layer.effect(ThreadObjectPorts)(Effect.gen(function* () {
|
|
244
|
+
const local = yield* Effect.context();
|
|
245
|
+
return ThreadObjectPorts.of({ handle: (request) => executePortRequest(request).pipe(Effect.provide(local)) });
|
|
246
|
+
})).pipe(Layer.provide(localPorts));
|
|
247
|
+
const routedPorts = Layer.mergeAll(routedSubmissionLedgerLayer({ localThreadId: threadId }), routedThreadStoreLayer({ localThreadId: threadId })).pipe(Layer.provide(localPorts), Layer.provide(threadPortTransportLayer));
|
|
248
|
+
const base = Layer.mergeAll(DurableAlarmService.layer, ProgressWaitRegistry.layer);
|
|
249
|
+
const runtimeStack = DurableAgentRuntime.layerWithServices.pipe(Layer.provideMerge(routedPorts), Layer.provideMerge(cloudflareWakeSchedulerLayer), Layer.provideMerge(base));
|
|
250
|
+
return Layer.mergeAll(runtimeStack, ThreadMaintenance.layer(bindings).pipe(Layer.provide(runtimeStack)), portsEndpointLayer);
|
|
251
|
+
}));
|
|
279
252
|
//#endregion
|
|
280
|
-
//#region src/
|
|
253
|
+
//#region src/thread-object.ts
|
|
254
|
+
var thread_object_exports = /* @__PURE__ */ __exportAll({
|
|
255
|
+
AdminExplainRequest: () => AdminExplainRequest,
|
|
256
|
+
AdminFailed: () => AdminFailed,
|
|
257
|
+
AdminFailure: () => AdminFailure,
|
|
258
|
+
AdminResponse: () => AdminResponse,
|
|
259
|
+
AdminVerifyRequest: () => AdminVerifyRequest,
|
|
260
|
+
ExplainedRecovery: () => ExplainedRecovery,
|
|
261
|
+
ObligationsScanned: () => ObligationsScanned,
|
|
262
|
+
RetryExecuted: () => RetryExecuted,
|
|
263
|
+
VerifiedIntegrity: () => VerifiedIntegrity,
|
|
264
|
+
decodeAdminExplainRequest: () => decodeAdminExplainRequest,
|
|
265
|
+
decodeAdminResponse: () => decodeAdminResponse,
|
|
266
|
+
decodeAdminVerifyRequest: () => decodeAdminVerifyRequest,
|
|
267
|
+
decodeObligationThresholds: () => decodeObligationThresholds,
|
|
268
|
+
decodeRetryCommand: () => decodeRetryCommand,
|
|
269
|
+
encodeAdminResponse: () => encodeAdminResponse,
|
|
270
|
+
layer: () => layer,
|
|
271
|
+
layerConfig: () => layerConfig,
|
|
272
|
+
make: () => make
|
|
273
|
+
});
|
|
281
274
|
/** Classify only a decoded port request so new protocol members cannot bypass pre-arming. */
|
|
282
275
|
const isMutatingPortRequest = (request) => {
|
|
283
276
|
switch (request._tag) {
|
|
@@ -321,13 +314,13 @@ const utf8Bytes = (value) => new TextEncoder().encode(JSON.stringify(value)).len
|
|
|
321
314
|
* exempt: its accepted-work obligation already exists, and returning the original Receipt
|
|
322
315
|
* consumes no new quota. Refusals are typed `AdmissionLimitExceeded` and nothing is written.
|
|
323
316
|
*/
|
|
324
|
-
const gateAdmissionLimits = Effect.fn("
|
|
325
|
-
const identity = yield*
|
|
317
|
+
const gateAdmissionLimits = Effect.fn("ThreadObject.gateAdmissionLimits")(function* (request) {
|
|
318
|
+
const identity = yield* ThreadObjectIdentity;
|
|
326
319
|
const config = yield* CloudflareDurableRuntimeConfig;
|
|
327
320
|
const ledger = yield* SubmissionLedger;
|
|
328
321
|
const { ctx } = yield* DurableObjectContext;
|
|
329
322
|
const existing = yield* ledger.lookup(SubmissionLookupByKey.make({
|
|
330
|
-
|
|
323
|
+
threadId: identity.threadId,
|
|
331
324
|
principal: request.principal,
|
|
332
325
|
idempotencyKey: request.idempotencyKey
|
|
333
326
|
}));
|
|
@@ -362,12 +355,12 @@ const passthroughSubmitAgent = (agentId) => ({ definition: {
|
|
|
362
355
|
input: PersistedJson
|
|
363
356
|
} });
|
|
364
357
|
const submitEndpoint = (encoded) => decodeSubmitRequest(encoded).pipe(Effect.mapError(protocolFailure("The submit request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
|
|
365
|
-
const identity = yield*
|
|
366
|
-
const maintenance = yield*
|
|
358
|
+
const identity = yield* ThreadObjectIdentity;
|
|
359
|
+
const maintenance = yield* ThreadMaintenance;
|
|
367
360
|
const runtime = yield* DurableAgentRuntime;
|
|
368
361
|
yield* gateAdmissionLimits(request);
|
|
369
362
|
const receipt = yield* maintenance.withMutation(runtime.submit(passthroughSubmitAgent(request.agentId), request.inputPayload, {
|
|
370
|
-
|
|
363
|
+
threadId: identity.threadId,
|
|
371
364
|
principal: request.principal,
|
|
372
365
|
idempotencyKey: request.idempotencyKey,
|
|
373
366
|
definitions: request.definitions
|
|
@@ -379,12 +372,12 @@ const awaitSettlementEndpoint = (encoded) => decodeReceipt(encoded).pipe(Effect.
|
|
|
379
372
|
return SettlementReached.make({ settlement });
|
|
380
373
|
})), respond, Effect.flatMap(encodeResponse));
|
|
381
374
|
const awaitProgressEndpoint = (encoded) => decodeAwaitProgressRequest(encoded).pipe(Effect.mapError(protocolFailure("The progress request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
|
|
382
|
-
const identity = yield*
|
|
375
|
+
const identity = yield* ThreadObjectIdentity;
|
|
383
376
|
const runtime = yield* DurableAgentRuntime;
|
|
384
377
|
const registry = yield* ProgressWaitRegistry;
|
|
385
378
|
yield* Effect.scoped(Effect.gen(function* () {
|
|
386
379
|
const cancelled = yield* registry.subscribe(request.waiterId);
|
|
387
|
-
yield* Effect.raceFirst(runtime.awaitProgress(identity.
|
|
380
|
+
yield* Effect.raceFirst(runtime.awaitProgress(identity.threadId, request.afterSequence), cancelled);
|
|
388
381
|
}));
|
|
389
382
|
return ProgressObserved.make();
|
|
390
383
|
})), respond, Effect.flatMap(encodeResponse));
|
|
@@ -393,33 +386,33 @@ const cancelProgressEndpoint = (encoded) => decodeCancelProgressRequest(encoded)
|
|
|
393
386
|
return ProgressCancelled.make();
|
|
394
387
|
})), respond, Effect.flatMap(encodeResponse));
|
|
395
388
|
const observePageEndpoint = (encoded) => decodeObservePageRequest(encoded).pipe(Effect.mapError(protocolFailure("The observe request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
|
|
396
|
-
const identity = yield*
|
|
397
|
-
const store = yield*
|
|
389
|
+
const identity = yield* ThreadObjectIdentity;
|
|
390
|
+
const store = yield* ThreadStore;
|
|
398
391
|
yield* (yield* OperationAuthorizer).authorize(OperationAuthorizationRequest.make({
|
|
399
392
|
operation: "observe",
|
|
400
|
-
|
|
393
|
+
threadId: identity.threadId
|
|
401
394
|
}));
|
|
402
|
-
const records = yield* Stream.runCollect(store.read(
|
|
403
|
-
|
|
395
|
+
const records = yield* Stream.runCollect(store.read(ThreadRead.make({
|
|
396
|
+
threadId: identity.threadId,
|
|
404
397
|
...request.afterSequence === void 0 ? {} : { afterSequence: request.afterSequence },
|
|
405
398
|
limit: request.limit
|
|
406
399
|
})));
|
|
407
400
|
return ObservedPage.make({ records: [...records] });
|
|
408
401
|
})), respond, Effect.flatMap(encodeResponse));
|
|
409
402
|
const abortEndpoint = (encoded) => decodeAbortCommand(encoded).pipe(Effect.mapError(protocolFailure("The abort command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
|
|
410
|
-
const maintenance = yield*
|
|
403
|
+
const maintenance = yield* ThreadMaintenance;
|
|
411
404
|
const runtime = yield* DurableAgentRuntime;
|
|
412
405
|
const intent = yield* maintenance.withMutation(runtime.abort(command));
|
|
413
406
|
return AbortRecorded.make({ intent });
|
|
414
407
|
})), respond, Effect.flatMap(encodeResponse));
|
|
415
408
|
const resolveApprovalEndpoint = (encoded) => decodeApprovalDecisionCommand(encoded).pipe(Effect.mapError(protocolFailure("The approval command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
|
|
416
|
-
const maintenance = yield*
|
|
409
|
+
const maintenance = yield* ThreadMaintenance;
|
|
417
410
|
const runtime = yield* DurableAgentRuntime;
|
|
418
411
|
const intent = yield* maintenance.withMutation(runtime.resolveApproval(command));
|
|
419
412
|
return ApprovalRecorded.make({ intent });
|
|
420
413
|
})), respond, Effect.flatMap(encodeResponse));
|
|
421
414
|
const resolveUnknownEndpoint = (encoded) => decodeUnknownResolutionCommand(encoded).pipe(Effect.mapError(protocolFailure("The resolution command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
|
|
422
|
-
const maintenance = yield*
|
|
415
|
+
const maintenance = yield* ThreadMaintenance;
|
|
423
416
|
const runtime = yield* DurableAgentRuntime;
|
|
424
417
|
const intent = yield* maintenance.withMutation(runtime.resolveUnknown(command));
|
|
425
418
|
return UnknownResolutionRecorded.make({ intent });
|
|
@@ -437,8 +430,8 @@ const AdminFailure = Schema.Union([
|
|
|
437
430
|
DigestError,
|
|
438
431
|
OwnershipLost,
|
|
439
432
|
SettlementConflict,
|
|
440
|
-
|
|
441
|
-
|
|
433
|
+
ThreadStoreError,
|
|
434
|
+
ThreadNotMaterialized,
|
|
442
435
|
AppendConflict,
|
|
443
436
|
FenceRejected,
|
|
444
437
|
DurableRuntimeFailpointError,
|
|
@@ -476,18 +469,18 @@ const encodeAdminResponseTotal = (response) => encodeAdminResponse(response).pip
|
|
|
476
469
|
}
|
|
477
470
|
})));
|
|
478
471
|
const explainEndpoint = (encoded) => decodeAdminExplainRequest(encoded).pipe(Effect.mapError(protocolFailure("The explain request could not be decoded")), Effect.flatMap((request) => Effect.gen(function* () {
|
|
479
|
-
const identity = yield*
|
|
472
|
+
const identity = yield* ThreadObjectIdentity;
|
|
480
473
|
const runtime = yield* DurableAgentRuntime;
|
|
481
|
-
const explanations = request.submissionId === void 0 ? yield* runtime.
|
|
474
|
+
const explanations = request.submissionId === void 0 ? yield* runtime.explainThread(identity.threadId) : [yield* runtime.explain(request.submissionId)];
|
|
482
475
|
return ExplainedRecovery.make({ explanations });
|
|
483
476
|
})), respondAdmin, Effect.flatMap(encodeAdminResponseTotal));
|
|
484
477
|
const verifyEndpoint = (encoded) => decodeAdminVerifyRequest(encoded).pipe(Effect.mapError(protocolFailure("The verify request could not be decoded")), Effect.flatMap(() => Effect.gen(function* () {
|
|
485
|
-
const identity = yield*
|
|
486
|
-
const report = yield* (yield* DurableAgentRuntime).verify(identity.
|
|
478
|
+
const identity = yield* ThreadObjectIdentity;
|
|
479
|
+
const report = yield* (yield* DurableAgentRuntime).verify(identity.threadId);
|
|
487
480
|
return VerifiedIntegrity.make({ report });
|
|
488
481
|
})), respondAdmin, Effect.flatMap(encodeAdminResponseTotal));
|
|
489
482
|
const retryEndpoint = (encoded) => decodeRetryCommand(encoded).pipe(Effect.mapError(protocolFailure("The retry command could not be decoded")), Effect.flatMap((command) => Effect.gen(function* () {
|
|
490
|
-
const maintenance = yield*
|
|
483
|
+
const maintenance = yield* ThreadMaintenance;
|
|
491
484
|
const runtime = yield* DurableAgentRuntime;
|
|
492
485
|
const report = yield* maintenance.withMutation(runtime.retry(command));
|
|
493
486
|
return RetryExecuted.make({ report });
|
|
@@ -504,8 +497,8 @@ const obligationsEndpoint = (encoded) => decodeObligationThresholds(encoded).pip
|
|
|
504
497
|
* `PortFailed(PortProtocolError)`.
|
|
505
498
|
*/
|
|
506
499
|
const portCallEndpoint = (encoded) => Effect.gen(function* () {
|
|
507
|
-
const ports = yield*
|
|
508
|
-
const maintenance = yield*
|
|
500
|
+
const ports = yield* ThreadObjectPorts;
|
|
501
|
+
const maintenance = yield* ThreadMaintenance;
|
|
509
502
|
const alarm = yield* DurableAlarmService;
|
|
510
503
|
const decoded = yield* decodePortRequest(encoded).pipe(Effect.map((request) => ({
|
|
511
504
|
_tag: "success",
|
|
@@ -519,18 +512,18 @@ const portCallEndpoint = (encoded) => Effect.gen(function* () {
|
|
|
519
512
|
const handled = yield* (mutating ? maintenance.withMutation(ports.handle(decoded.request)) : ports.handle(decoded.request)).pipe(Effect.exit);
|
|
520
513
|
if (handled._tag === "Failure") return encodedPortProtocolFailure("The owner Object could not arm its maintenance alarm before the mutation.");
|
|
521
514
|
const response = yield* encodePortResponse(handled.value).pipe(Effect.catch((error) => Effect.succeed(encodedPortProtocolFailure(`The port response could not be encoded: ${error.message}`))));
|
|
522
|
-
if (mutating) yield* alarm.scheduleNow.pipe(Effect.catch((error) => Effect.logWarning("
|
|
515
|
+
if (mutating) yield* alarm.scheduleNow.pipe(Effect.catch((error) => Effect.logWarning("ThreadObject.portCall: immediate re-arm failed", error)));
|
|
523
516
|
return response;
|
|
524
517
|
});
|
|
525
518
|
const wakeEndpoint = Effect.gen(function* () {
|
|
526
|
-
const identity = yield*
|
|
527
|
-
yield* (yield* WakeScheduler).notify(identity.
|
|
519
|
+
const identity = yield* ThreadObjectIdentity;
|
|
520
|
+
yield* (yield* WakeScheduler).notify(identity.threadId);
|
|
528
521
|
});
|
|
529
522
|
const alarmEndpoint = Effect.gen(function* () {
|
|
530
|
-
yield* (yield*
|
|
523
|
+
yield* (yield* ThreadMaintenance).pass;
|
|
531
524
|
});
|
|
532
525
|
const gateEndpoint = Effect.gen(function* () {
|
|
533
|
-
yield* (yield*
|
|
526
|
+
yield* (yield* ThreadMaintenance).ensureAlarm;
|
|
534
527
|
});
|
|
535
528
|
/**
|
|
536
529
|
* Adapter from effect-cf's native Durable Object services to Effect Agent's existing platform
|
|
@@ -546,9 +539,10 @@ const effectCfPlatformLayer = (namespaceBinding, rpcTracing = false) => {
|
|
|
546
539
|
env
|
|
547
540
|
});
|
|
548
541
|
}));
|
|
549
|
-
const namespace = Layer.effect(
|
|
550
|
-
const
|
|
551
|
-
|
|
542
|
+
const namespace = Layer.effect(ThreadObjectNamespace)(Effect.gen(function* () {
|
|
543
|
+
const env = yield* WorkerEnvironment;
|
|
544
|
+
const binding = yield* threadNamespaceFromEnv(env, namespaceBinding);
|
|
545
|
+
return ThreadObjectNamespace.of({
|
|
552
546
|
namespace: binding,
|
|
553
547
|
...rpcTracing === true ? { rpcTracing: namespaceBinding } : {}
|
|
554
548
|
});
|
|
@@ -556,14 +550,16 @@ const effectCfPlatformLayer = (namespaceBinding, rpcTracing = false) => {
|
|
|
556
550
|
return Layer.merge(context, namespace);
|
|
557
551
|
};
|
|
558
552
|
/**
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
562
|
-
*
|
|
563
|
-
*
|
|
553
|
+
* Export a composed application Layer as a native Durable Object class.
|
|
554
|
+
* Bootstrap services are provided to the whole graph before it acquires, so application Layers
|
|
555
|
+
* can yield effect-cf's WorkerEnvironment and DurableObjectState, derived identity, and Crypto.
|
|
556
|
+
* Application dependencies remain visible until Layer.provide satisfies them. effect-cf owns the
|
|
557
|
+
* cached ManagedRuntime, native RPC methods, event scopes, and telemetry flushing.
|
|
558
|
+
* Initialization is local and bounded inside the constructor gate. Cloudflare eviction does not
|
|
559
|
+
* guarantee finalizers; put resources requiring timely release in scoped operations or eventLayer.
|
|
564
560
|
*/
|
|
565
|
-
const
|
|
566
|
-
const application =
|
|
561
|
+
const make = (applicationLayer, options) => {
|
|
562
|
+
const application = applicationLayer.pipe(Layer.provideMerge(layerConfig(options)), Layer.provideMerge(effectCfPlatformLayer(options.namespaceBinding, options.rpcTracing)));
|
|
567
563
|
const runtime = Layer.effectContext(Effect.gen(function* () {
|
|
568
564
|
const state = yield* DurableObjectState.DurableObjectState;
|
|
569
565
|
const scope = yield* Effect.scope;
|
|
@@ -589,19 +585,19 @@ const makeConversationObjectClass = (options, observability) => {
|
|
|
589
585
|
portCall: (encoded) => portCallEndpoint(encoded),
|
|
590
586
|
wake: () => wakeEndpoint
|
|
591
587
|
};
|
|
592
|
-
const
|
|
588
|
+
const EffectCfThreadObject = DurableObject.make(runtime, {
|
|
593
589
|
...options.rpcTracing === true ? { rpcTracing: { service: options.namespaceBinding } } : {},
|
|
594
|
-
...
|
|
590
|
+
...options.eventLayer === void 0 ? {} : { eventLayer: options.eventLayer },
|
|
595
591
|
initialize: Effect.void,
|
|
596
592
|
rpc,
|
|
597
593
|
alarm: () => alarmEndpoint
|
|
598
594
|
});
|
|
599
|
-
class
|
|
595
|
+
class ThreadObject extends EffectCfThreadObject {
|
|
600
596
|
alarm(alarmInfo) {
|
|
601
597
|
return super.alarm?.(alarmInfo);
|
|
602
598
|
}
|
|
603
599
|
}
|
|
604
|
-
return
|
|
600
|
+
return ThreadObject;
|
|
605
601
|
};
|
|
606
602
|
//#endregion
|
|
607
603
|
//#region src/code-mode-executor.ts
|
|
@@ -787,7 +783,7 @@ export default class CodeModeHarness extends WorkerEntrypoint {
|
|
|
787
783
|
}
|
|
788
784
|
}
|
|
789
785
|
`;
|
|
790
|
-
const BoundedLogs = Schema.Array(Schema.String.check(Schema.isMaxLength(
|
|
786
|
+
const BoundedLogs = Schema.Array(Schema.String.check(Schema.isMaxLength(16384))).check(Schema.isMaxLength(4096));
|
|
791
787
|
const HarnessCompleted = Schema.TaggedStruct("completed", {
|
|
792
788
|
value: Schema.Json,
|
|
793
789
|
logs: BoundedLogs,
|
|
@@ -1198,7 +1194,15 @@ const dynamicWorkerCodeExecutorLayer = (options) => Layer.effect(CodeExecutor, E
|
|
|
1198
1194
|
const clock = yield* Clock.Clock;
|
|
1199
1195
|
return CodeExecutor.of({ execute: makeExecute(options, clock) });
|
|
1200
1196
|
}));
|
|
1197
|
+
/** Assemble Code Mode handlers with the isolated Dynamic Worker executor. */
|
|
1198
|
+
const CloudflareCodeMode = {
|
|
1199
|
+
/**
|
|
1200
|
+
* Provide the selected tool handlers at construction, where Code Mode captures them.
|
|
1201
|
+
* Their errors and remaining dependencies stay visible. The definition still owns the
|
|
1202
|
+
* allowlist and limits; the runtime supplies the live Tool broker for each scoped pass.
|
|
1203
|
+
*/
|
|
1204
|
+
layer: (definition, options) => definition.handlers.pipe(Layer.provide(options.handlers), Layer.provide(dynamicWorkerCodeExecutorLayer(options))) };
|
|
1201
1205
|
//#endregion
|
|
1202
|
-
export { AbortRecorded,
|
|
1206
|
+
export { AbortRecorded, AdmissionLimitExceeded, ApprovalRecorded, AwaitProgressRequest, CLOUDFLARE_DATABASE_CAP_BYTES, CLOUDFLARE_RUNTIME_DEFAULTS, CancelProgressRequest, CloudflareAdmissionLimitsValue, CloudflareBindingError, CloudflareBrowser, CloudflareCodeMode, CloudflareDurableRuntimeConfig, CloudflareDurableRuntimeConfigValue, CloudflarePlatformConfigError, CloudflareSchedulingClient, CloudflareSubscriptionConfigError, CloudflareSubscriptionsClient, CloudflareThreadClient, DEFAULT_MAX_DATABASE_BYTES, DurableAlarmError, DurableAlarmService, DurableObjectContext, HostFailed, HostFailure, HostProtocolError, HostResponse, MaintenancePassReport, ObservePageRequest, ObservedPage, ProgressCancelled, ProgressObserved, ProgressWaitRegistry, ScheduleAlarmProtocolError, ScheduleOwnerIdentity, ScheduleOwnerNamespace, ScheduleOwnerProtocolError, SettlementReached, SubmitRequest, SubmitSucceeded, SubscriptionAlarmProtocolError, SubscriptionPartitionIdentity, SubscriptionPartitionNamespace, SubscriptionPartitionProtocolError, ThreadClientError, ThreadMaintenance, ThreadMaintenanceFailpoint, thread_object_exports as ThreadObject, ThreadObjectIdentity, ThreadObjectNamespace, ThreadObjectPorts, UnknownResolutionRecorded, boundHostDiagnostic, cloudflarePreparedInputAdmissionLayer, cloudflareScheduledInputAdmissionLayer, cloudflareWakeSchedulerLayer, decodeAbortCommand, decodeApprovalDecisionCommand, decodeAwaitProgressRequest, decodeCancelProgressRequest, decodeHostResponse, decodeObservePageRequest, decodeReceipt, decodeSubmitRequest, decodeUnknownResolutionCommand, disposeRpcHandle, dynamicWorkerCodeExecutorLayer, dynamicWorkerImplementation, encodeAbortCommand, encodeApprovalDecisionCommand, encodeAwaitProgressRequest, encodeCancelProgressRequest, encodeHostResponse, encodeObservePageRequest, encodeReceipt, encodeSubmitRequest, encodeUnknownResolutionCommand, makeScheduleOwnerObjectClass, makeSubscriptionPartitionObjectClass, sourcePartitionName, threadNamespaceFromEnv, threadNamespaceLayer, threadPortTransportLayer, validateCloudflareSubscriptionLimits };
|
|
1203
1207
|
|
|
1204
1208
|
//# sourceMappingURL=index.mjs.map
|