@effect-agent/platform-cloudflare 0.1.0-beta.8 → 0.1.0-beta.80
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/Alarm.d.mts +183 -0
- package/dist/Alarm.mjs +454 -0
- package/dist/Alarm.mjs.map +1 -0
- package/dist/BrowserRestCapture.d.mts +35 -0
- package/dist/BrowserRestCapture.mjs +238 -0
- package/dist/BrowserRestCapture.mjs.map +1 -0
- package/dist/BrowserRestCrawl.d.mts +17 -0
- package/dist/BrowserRestCrawl.mjs +244 -0
- package/dist/BrowserRestCrawl.mjs.map +1 -0
- package/dist/CloudflareAiGateway.d.mts +64 -0
- package/dist/CloudflareAiGateway.mjs +70 -0
- package/dist/CloudflareAiGateway.mjs.map +1 -0
- package/dist/CloudflareBindings.d.mts +112 -0
- package/dist/CloudflareBindings.mjs +101 -0
- package/dist/CloudflareBindings.mjs.map +1 -0
- package/dist/CloudflareBrowser-D4YqaTAl.mjs +495 -0
- package/dist/CloudflareBrowser-D4YqaTAl.mjs.map +1 -0
- package/dist/CloudflareBrowser-DJq53niJ.d.mts +80 -0
- package/dist/CloudflareBrowser.d.mts +2 -0
- package/dist/CloudflareBrowser.mjs +2 -0
- package/dist/CloudflareCodeMode.d.mts +44 -0
- package/dist/CloudflareCodeMode.mjs +616 -0
- package/dist/CloudflareCodeMode.mjs.map +1 -0
- package/dist/CloudflareConfig-f3CqTel1.d.mts +101 -0
- package/dist/CloudflareConfig.d.mts +2 -0
- package/dist/CloudflareConfig.mjs +122 -0
- package/dist/CloudflareConfig.mjs.map +1 -0
- package/dist/CloudflareMemory.d.mts +142 -0
- package/dist/CloudflareMemory.mjs +195 -0
- package/dist/CloudflareMemory.mjs.map +1 -0
- package/dist/CloudflareScheduling.d.mts +52 -0
- package/dist/CloudflareScheduling.mjs +389 -0
- package/dist/CloudflareScheduling.mjs.map +1 -0
- package/dist/CloudflareSubscriptions.d.mts +87 -0
- package/dist/CloudflareSubscriptions.mjs +524 -0
- package/dist/CloudflareSubscriptions.mjs.map +1 -0
- package/dist/CloudflareThreadClient.d.mts +1286 -0
- package/dist/CloudflareThreadClient.mjs +386 -0
- package/dist/CloudflareThreadClient.mjs.map +1 -0
- package/dist/InteractiveBrowser.d.mts +144 -0
- package/dist/InteractiveBrowser.mjs +1090 -0
- package/dist/InteractiveBrowser.mjs.map +1 -0
- package/dist/ProtectedBrowser.d.mts +65 -0
- package/dist/ProtectedBrowser.mjs +859 -0
- package/dist/ProtectedBrowser.mjs.map +1 -0
- package/dist/ThreadObject-3uDpKfB3.d.mts +816 -0
- package/dist/ThreadObject-DGkXv41C.mjs +836 -0
- package/dist/ThreadObject-DGkXv41C.mjs.map +1 -0
- package/dist/ThreadObject.d.mts +2 -0
- package/dist/ThreadObject.mjs +3 -0
- package/dist/WakeScheduler.d.mts +23 -0
- package/dist/WakeScheduler.mjs +60 -0
- package/dist/WakeScheduler.mjs.map +1 -0
- package/dist/boundary-BguazVkh.mjs +42 -0
- package/dist/boundary-BguazVkh.mjs.map +1 -0
- package/dist/browser-session-lifecycle-CUbVfEgP.mjs +84 -0
- package/dist/browser-session-lifecycle-CUbVfEgP.mjs.map +1 -0
- package/dist/browser-session-lifecycle-DJpqLXy_.d.mts +21 -0
- package/dist/index.d.mts +13 -1547
- package/dist/index.mjs +13 -1636
- package/dist/prepared-admission-DSi55W-7.mjs +73 -0
- package/dist/prepared-admission-DSi55W-7.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/package.json +1 -53
- package/src/Alarm.ts +953 -0
- package/src/BrowserRestCapture.ts +477 -0
- package/src/BrowserRestCrawl.ts +540 -0
- package/src/CloudflareAiGateway.ts +170 -0
- package/src/CloudflareBindings.ts +180 -0
- package/src/CloudflareBrowser.ts +15 -0
- package/src/{code-mode-executor.ts → CloudflareCodeMode.ts} +372 -204
- package/src/{config.ts → CloudflareConfig.ts} +9 -8
- package/src/CloudflareMemory.ts +406 -0
- package/src/CloudflareScheduling.ts +733 -0
- package/src/CloudflareSubscriptions.ts +1045 -0
- package/src/CloudflareThreadClient.ts +807 -0
- package/src/InteractiveBrowser.ts +2357 -0
- package/src/ProtectedBrowser.ts +2 -0
- package/src/ThreadObject.ts +1179 -0
- package/src/{wake-scheduler.ts → WakeScheduler.ts} +23 -23
- package/src/index.ts +12 -23
- package/src/internal/boundary.ts +55 -0
- package/src/internal/browser-quick-action.ts +857 -0
- package/src/internal/browser-session-lifecycle.ts +160 -0
- package/src/internal/layers.ts +751 -0
- package/src/internal/message-delivery.ts +148 -0
- package/src/internal/prepared-admission.ts +116 -0
- package/src/internal/progress-wait.ts +121 -0
- package/src/internal/transport.ts +42 -0
- package/src/protected-browser/binding.ts +187 -0
- package/src/protected-browser/inspect-frame.ts +125 -0
- package/src/protected-browser/native.ts +429 -0
- package/src/protected-browser/policy.ts +719 -0
- package/dist/index.mjs.map +0 -1
- package/src/alarm.ts +0 -334
- package/src/bindings.ts +0 -145
- package/src/client.ts +0 -646
- package/src/conversation-object.ts +0 -768
- package/src/layers.ts +0 -376
- package/src/transport.ts +0 -38
package/src/layers.ts
DELETED
|
@@ -1,376 +0,0 @@
|
|
|
1
|
-
import { ConversationId } from "@effect-agent/core";
|
|
2
|
-
import {
|
|
3
|
-
AgentBindingResolver,
|
|
4
|
-
ConversationStore,
|
|
5
|
-
DurableAgentRuntime,
|
|
6
|
-
DurableRuntimeConfig,
|
|
7
|
-
DurableRuntimeFailpoint,
|
|
8
|
-
ProducerId,
|
|
9
|
-
SubmissionLedger,
|
|
10
|
-
ToolReconciler,
|
|
11
|
-
WakeScheduler,
|
|
12
|
-
type DurableRuntimeFailpointHandler,
|
|
13
|
-
type ResolvedBinding,
|
|
14
|
-
} from "@effect-agent/session";
|
|
15
|
-
import {
|
|
16
|
-
conversationStoreLayer,
|
|
17
|
-
handleEncodedPortRequest,
|
|
18
|
-
routedConversationStoreLayer,
|
|
19
|
-
routedSubmissionLedgerLayer,
|
|
20
|
-
storageConfigLayer,
|
|
21
|
-
storageFailpointLayer,
|
|
22
|
-
submissionLedgerLayer,
|
|
23
|
-
type DoStorageFailpointHandler,
|
|
24
|
-
type DoStorageInitializationError,
|
|
25
|
-
type DoStorageOptions,
|
|
26
|
-
} from "@effect-agent/storage-cloudflare";
|
|
27
|
-
import { BrowserCrypto } from "@effect/platform-browser";
|
|
28
|
-
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
29
|
-
import { Context, Duration, Effect, Layer, Schema } from "effect";
|
|
30
|
-
|
|
31
|
-
import { ConversationMaintenance, DurableAlarmService } from "./alarm.ts";
|
|
32
|
-
import {
|
|
33
|
-
ConversationObjectIdentity,
|
|
34
|
-
ConversationObjectNamespace,
|
|
35
|
-
DurableObjectContext,
|
|
36
|
-
} from "./bindings.ts";
|
|
37
|
-
import {
|
|
38
|
-
CLOUDFLARE_RUNTIME_DEFAULTS,
|
|
39
|
-
CloudflareDurableRuntimeConfig,
|
|
40
|
-
CloudflareDurableRuntimeConfigValue,
|
|
41
|
-
CloudflarePlatformConfigError,
|
|
42
|
-
} from "./config.ts";
|
|
43
|
-
import { conversationPortTransportLayer } from "./transport.ts";
|
|
44
|
-
import { cloudflareWakeSchedulerLayer } from "./wake-scheduler.ts";
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Raw (unvalidated) construction options for `CloudflareDurableRuntime.layer`, mirroring
|
|
48
|
-
* `NodeDurableRuntimeOptions`. Optional fields default to the documented production values
|
|
49
|
-
* (`CLOUDFLARE_RUNTIME_DEFAULTS`); everything is schema-decoded into
|
|
50
|
-
* `CloudflareDurableRuntimeConfigValue` before any resource opens (deployment §5 gate 1).
|
|
51
|
-
*/
|
|
52
|
-
export interface CloudflareDurableRuntimeOptions {
|
|
53
|
-
readonly deploymentId: string;
|
|
54
|
-
/** Head of the minted producer identity `{producerPrefix}:{conversationId}`. */
|
|
55
|
-
readonly producerPrefix: string;
|
|
56
|
-
/** Milliseconds; default 30s (D5). */
|
|
57
|
-
readonly ownershipLeaseDuration?: number | undefined;
|
|
58
|
-
/** Milliseconds; default 100. */
|
|
59
|
-
readonly alarmBackoffBase?: number | undefined;
|
|
60
|
-
/** Milliseconds; default 5000. */
|
|
61
|
-
readonly alarmBackoffCap?: number | undefined;
|
|
62
|
-
/** Milliseconds; default 1000. Bounds every alarm re-arm delay. */
|
|
63
|
-
readonly wakeScanInterval?: number | undefined;
|
|
64
|
-
/** Milliseconds; default 500. */
|
|
65
|
-
readonly settlementPollInterval?: number | undefined;
|
|
66
|
-
/** Milliseconds; default 10000. */
|
|
67
|
-
readonly leaseRenewalInterval?: number | undefined;
|
|
68
|
-
/** Milliseconds; default 500. */
|
|
69
|
-
readonly abortPollInterval?: number | undefined;
|
|
70
|
-
/** Milliseconds; default 25. */
|
|
71
|
-
readonly observationPollInterval?: number | undefined;
|
|
72
|
-
/** Bytes; default just under the 2 MB platform value limit. */
|
|
73
|
-
readonly maxStoredValueBytes?: number | undefined;
|
|
74
|
-
/** Default false. */
|
|
75
|
-
readonly verifyOnOpen?: boolean | undefined;
|
|
76
|
-
/** Nonterminal Submissions per lane before admission refuses; default 256. */
|
|
77
|
-
readonly maxQueueDepthPerLane?: number | undefined;
|
|
78
|
-
/** Encoded input bytes per Submission; default = the stored-value bound. */
|
|
79
|
-
readonly maxInputBytes?: number | undefined;
|
|
80
|
-
/** `ctx.storage.sql.databaseSize` ceiling at admission; default 9 GB (10 GB platform cap). */
|
|
81
|
-
readonly maxDatabaseBytes?: number | undefined;
|
|
82
|
-
/**
|
|
83
|
-
* Durable Object storage fault injection (`ledger:*` / `append:*` locations). Handlers are
|
|
84
|
-
* constructed per incarnation WITH the live `DurableObjectState`, so eviction harnesses can
|
|
85
|
-
* map an armed hit to `ctx.abort()` — the platform's real failure mode. Default none.
|
|
86
|
-
*/
|
|
87
|
-
readonly storageFailpoint?: ((ctx: DurableObjectState) => DoStorageFailpointHandler) | undefined;
|
|
88
|
-
/** Coordinator fault injection (`submit:*` / `terminalize:*` locations); default none. */
|
|
89
|
-
readonly runtimeFailpoint?:
|
|
90
|
-
| ((ctx: DurableObjectState) => DurableRuntimeFailpointHandler)
|
|
91
|
-
| undefined;
|
|
92
|
-
/**
|
|
93
|
-
* Reconciliation policy consulted for open ordinary Tool Calls before an Unknown Outcome
|
|
94
|
-
* is recorded (durability §10, DUR-009). Defaults to the fail-closed
|
|
95
|
-
* `ToolReconciler.uncertain`.
|
|
96
|
-
*/
|
|
97
|
-
readonly toolReconciler?: Layer.Layer<ToolReconciler> | undefined;
|
|
98
|
-
/**
|
|
99
|
-
* Registered worker Bindings resolved at durable claim time (S2, spec/subagents.md §11):
|
|
100
|
-
* build each with `DurableWorkerBinding.make(binding, digests)`. An Effect or callback form is
|
|
101
|
-
* accepted because capture can be effectful. The callback receives the live Object context and
|
|
102
|
-
* derived identities and is evaluated once per incarnation during Layer construction. Defaults
|
|
103
|
-
* to the empty registration (every resolved claim fails closed).
|
|
104
|
-
*/
|
|
105
|
-
readonly bindings?: CloudflareBindingSource | undefined;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** Per-incarnation host values available while registered worker Bindings are captured. */
|
|
109
|
-
export interface CloudflareBindingSourceContext {
|
|
110
|
-
readonly ctx: DurableObjectState;
|
|
111
|
-
readonly env: unknown;
|
|
112
|
-
readonly conversationId: ConversationId;
|
|
113
|
-
readonly producerId: ProducerId;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Registered worker Bindings, or a closed Effect/callback that captures them once for each
|
|
118
|
-
* Durable Object incarnation. Callback Effects cannot require services or fail typed.
|
|
119
|
-
*/
|
|
120
|
-
export type CloudflareBindingSource =
|
|
121
|
-
| ReadonlyArray<ResolvedBinding>
|
|
122
|
-
| Effect.Effect<ReadonlyArray<ResolvedBinding>, never, never>
|
|
123
|
-
| ((
|
|
124
|
-
context: CloudflareBindingSourceContext,
|
|
125
|
-
) =>
|
|
126
|
-
| ReadonlyArray<ResolvedBinding>
|
|
127
|
-
| Effect.Effect<ReadonlyArray<ResolvedBinding>, never, never>);
|
|
128
|
-
|
|
129
|
-
/** Every construction failure of the assembled Cloudflare durable runtime stack. */
|
|
130
|
-
export type CloudflareDurableRuntimeInitializationError =
|
|
131
|
-
| CloudflarePlatformConfigError
|
|
132
|
-
| DoStorageInitializationError;
|
|
133
|
-
|
|
134
|
-
/** The services `CloudflareDurableRuntime.layer` provides. */
|
|
135
|
-
export type CloudflareDurableRuntimeServices =
|
|
136
|
-
| DurableAgentRuntime
|
|
137
|
-
| SubmissionLedger
|
|
138
|
-
| ConversationStore
|
|
139
|
-
| WakeScheduler
|
|
140
|
-
| DurableRuntimeConfig
|
|
141
|
-
| AgentBindingResolver
|
|
142
|
-
| CloudflareDurableRuntimeConfig
|
|
143
|
-
| ConversationObjectIdentity
|
|
144
|
-
| DurableAlarmService
|
|
145
|
-
| ConversationMaintenance
|
|
146
|
-
| ConversationObjectPorts;
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Owner-side endpoint body for the Conversation Object's `portCall` (plan §1.3): decode,
|
|
150
|
-
* execute against THIS Object's LOCAL port facets — never the routed decorators, so a
|
|
151
|
-
* request cannot bounce between Objects — and answer the encoded response envelope. Total by
|
|
152
|
-
* construction (protocol anomalies answer `PortFailed(PortProtocolError)`).
|
|
153
|
-
*/
|
|
154
|
-
export class ConversationObjectPorts extends Context.Service<
|
|
155
|
-
ConversationObjectPorts,
|
|
156
|
-
{
|
|
157
|
-
readonly handle: (encoded: unknown) => Effect.Effect<unknown>;
|
|
158
|
-
}
|
|
159
|
-
>()("@effect-agent/platform-cloudflare/ConversationObjectPorts") {}
|
|
160
|
-
|
|
161
|
-
const decodeConfigValue = Schema.decodeUnknownEffect(CloudflareDurableRuntimeConfigValue);
|
|
162
|
-
const decodeConversationId = Schema.decodeUnknownEffect(ConversationId);
|
|
163
|
-
const decodeProducerId = Schema.decodeUnknownEffect(ProducerId);
|
|
164
|
-
|
|
165
|
-
const configFromOptions = (
|
|
166
|
-
options: CloudflareDurableRuntimeOptions,
|
|
167
|
-
): Effect.Effect<CloudflareDurableRuntimeConfigValue, CloudflarePlatformConfigError> =>
|
|
168
|
-
decodeConfigValue({
|
|
169
|
-
deploymentId: options.deploymentId,
|
|
170
|
-
producerPrefix: options.producerPrefix,
|
|
171
|
-
ownershipLeaseDuration:
|
|
172
|
-
options.ownershipLeaseDuration ?? CLOUDFLARE_RUNTIME_DEFAULTS.ownershipLeaseDuration,
|
|
173
|
-
alarmBackoffBase: options.alarmBackoffBase ?? CLOUDFLARE_RUNTIME_DEFAULTS.alarmBackoffBase,
|
|
174
|
-
alarmBackoffCap: options.alarmBackoffCap ?? CLOUDFLARE_RUNTIME_DEFAULTS.alarmBackoffCap,
|
|
175
|
-
wakeScanInterval: options.wakeScanInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.wakeScanInterval,
|
|
176
|
-
settlementPollInterval:
|
|
177
|
-
options.settlementPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.settlementPollInterval,
|
|
178
|
-
leaseRenewalInterval:
|
|
179
|
-
options.leaseRenewalInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.leaseRenewalInterval,
|
|
180
|
-
abortPollInterval: options.abortPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.abortPollInterval,
|
|
181
|
-
observationPollInterval:
|
|
182
|
-
options.observationPollInterval ?? CLOUDFLARE_RUNTIME_DEFAULTS.observationPollInterval,
|
|
183
|
-
maxStoredValueBytes:
|
|
184
|
-
options.maxStoredValueBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxStoredValueBytes,
|
|
185
|
-
verifyOnOpen: options.verifyOnOpen ?? CLOUDFLARE_RUNTIME_DEFAULTS.verifyOnOpen,
|
|
186
|
-
limits: {
|
|
187
|
-
maxQueueDepthPerLane:
|
|
188
|
-
options.maxQueueDepthPerLane ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxQueueDepthPerLane,
|
|
189
|
-
maxInputBytes: Math.min(
|
|
190
|
-
options.maxInputBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxInputBytes,
|
|
191
|
-
options.maxStoredValueBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxStoredValueBytes,
|
|
192
|
-
),
|
|
193
|
-
maxDatabaseBytes: options.maxDatabaseBytes ?? CLOUDFLARE_RUNTIME_DEFAULTS.maxDatabaseBytes,
|
|
194
|
-
},
|
|
195
|
-
}).pipe(
|
|
196
|
-
Effect.mapError((error) =>
|
|
197
|
-
CloudflarePlatformConfigError.make({
|
|
198
|
-
message: `Invalid Cloudflare durable runtime configuration: ${error.message}`,
|
|
199
|
-
cause: error,
|
|
200
|
-
}),
|
|
201
|
-
),
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* The Conversation this Object owns, from the Object identity rule (plan §1.2): Conversation
|
|
206
|
-
* Objects are addressed exclusively by `idFromName(conversationId)`, so `ctx.id.name` IS the
|
|
207
|
-
* Conversation ID. An unnamed Object (from `newUniqueId`) is a deployment error, not a lane.
|
|
208
|
-
*/
|
|
209
|
-
const conversationIdFromState = (
|
|
210
|
-
ctx: DurableObjectState,
|
|
211
|
-
): Effect.Effect<ConversationId, CloudflarePlatformConfigError> =>
|
|
212
|
-
ctx.id.name === undefined
|
|
213
|
-
? Effect.fail(
|
|
214
|
-
CloudflarePlatformConfigError.make({
|
|
215
|
-
message:
|
|
216
|
-
"This Durable Object was not created via idFromName(conversationId); Conversation " +
|
|
217
|
-
"Objects must be addressed by their Conversation identity (plan §1.2).",
|
|
218
|
-
}),
|
|
219
|
-
)
|
|
220
|
-
: decodeConversationId(ctx.id.name).pipe(
|
|
221
|
-
Effect.mapError((error) =>
|
|
222
|
-
CloudflarePlatformConfigError.make({
|
|
223
|
-
message: `The Durable Object name is not a valid ConversationId: ${error.message}`,
|
|
224
|
-
cause: error,
|
|
225
|
-
}),
|
|
226
|
-
),
|
|
227
|
-
);
|
|
228
|
-
|
|
229
|
-
const resolveBindings = (
|
|
230
|
-
source: CloudflareDurableRuntimeOptions["bindings"],
|
|
231
|
-
context: CloudflareBindingSourceContext,
|
|
232
|
-
): Effect.Effect<ReadonlyArray<ResolvedBinding>> =>
|
|
233
|
-
source === undefined
|
|
234
|
-
? Effect.succeed([])
|
|
235
|
-
: Effect.isEffect(source)
|
|
236
|
-
? source
|
|
237
|
-
: typeof source === "function"
|
|
238
|
-
? Effect.suspend(() => {
|
|
239
|
-
const bindings = source(context);
|
|
240
|
-
return Effect.isEffect(bindings) ? bindings : Effect.succeed(bindings);
|
|
241
|
-
})
|
|
242
|
-
: Effect.succeed(source);
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* The DC Layer assembly (deployment §12: a Layer-assembly library, not an app entrypoint;
|
|
246
|
-
* plan §1.4). `layer(options)` decodes the configuration, derives this Object's Conversation
|
|
247
|
-
* and producer identities, opens the Object's private SQLite database through
|
|
248
|
-
* `@effect/sql-sqlite-do` for BOTH the Conversation Log and the Submission Ledger (so claims
|
|
249
|
-
* fence the same producer epochs — ADR-0011 D7 transposed), wraps the local port facets with
|
|
250
|
-
* the WP2 cross-Object routing decorators over the Durable Object RPC transport, wires the
|
|
251
|
-
* alarm-backed wake scheduler and the maintenance pass, defaults reconciliation to the
|
|
252
|
-
* fail-closed `ToolReconciler.uncertain`, and provides a ready `DurableAgentRuntime` on top.
|
|
253
|
-
*
|
|
254
|
-
* Storage compatibility is verified during construction: an incompatible database fails the
|
|
255
|
-
* Layer typed (`DoStorageCompatibilityError`) before anything is mutated (DEPLOY-008).
|
|
256
|
-
*
|
|
257
|
-
* Requires only the two binding services (`DurableObjectContext`,
|
|
258
|
-
* `ConversationObjectNamespace`) — platform values enter exclusively through Layers
|
|
259
|
-
* (DEPLOY-010).
|
|
260
|
-
*/
|
|
261
|
-
export class CloudflareDurableRuntime {
|
|
262
|
-
static layer(
|
|
263
|
-
options: CloudflareDurableRuntimeOptions,
|
|
264
|
-
): Layer.Layer<
|
|
265
|
-
CloudflareDurableRuntimeServices,
|
|
266
|
-
CloudflareDurableRuntimeInitializationError,
|
|
267
|
-
DurableObjectContext | ConversationObjectNamespace
|
|
268
|
-
> {
|
|
269
|
-
return Layer.unwrap(
|
|
270
|
-
Effect.gen(function* () {
|
|
271
|
-
const { ctx, env } = yield* DurableObjectContext;
|
|
272
|
-
const config = yield* configFromOptions(options);
|
|
273
|
-
const conversationId = yield* conversationIdFromState(ctx);
|
|
274
|
-
const producerId = yield* decodeProducerId(
|
|
275
|
-
`${config.producerPrefix}:${conversationId}`,
|
|
276
|
-
).pipe(
|
|
277
|
-
Effect.mapError((error) =>
|
|
278
|
-
CloudflarePlatformConfigError.make({
|
|
279
|
-
message: `The minted producer identity is invalid: ${error.message}`,
|
|
280
|
-
cause: error,
|
|
281
|
-
}),
|
|
282
|
-
),
|
|
283
|
-
);
|
|
284
|
-
|
|
285
|
-
const identityLayer = Layer.succeed(ConversationObjectIdentity)({
|
|
286
|
-
conversationId,
|
|
287
|
-
producerId,
|
|
288
|
-
});
|
|
289
|
-
const cloudflareConfigLayer = Layer.succeed(CloudflareDurableRuntimeConfig)(config);
|
|
290
|
-
|
|
291
|
-
const storageOptions: DoStorageOptions = {
|
|
292
|
-
storage: ctx.storage,
|
|
293
|
-
observationPollInterval: config.observationPollInterval,
|
|
294
|
-
ownershipLeaseDuration: config.ownershipLeaseDuration,
|
|
295
|
-
maxStoredValueBytes: config.maxStoredValueBytes,
|
|
296
|
-
verifyOnOpen: config.verifyOnOpen,
|
|
297
|
-
failpoint: options.storageFailpoint?.(ctx),
|
|
298
|
-
};
|
|
299
|
-
const infrastructure = Layer.mergeAll(
|
|
300
|
-
storageConfigLayer(storageOptions),
|
|
301
|
-
storageFailpointLayer(storageOptions),
|
|
302
|
-
SqliteClient.layer({ storage: ctx.storage }),
|
|
303
|
-
BrowserCrypto.layer,
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* ONE local-facet instance (a shared Layer value) serves both the routed decorators
|
|
308
|
-
* and the owner-side `portCall` executor — the executor must never see the routed
|
|
309
|
-
* ports (plan §1.3: re-routing could bounce a request between Objects).
|
|
310
|
-
*/
|
|
311
|
-
const localPorts = Layer.mergeAll(conversationStoreLayer, submissionLedgerLayer).pipe(
|
|
312
|
-
Layer.provide(infrastructure),
|
|
313
|
-
);
|
|
314
|
-
|
|
315
|
-
const portsEndpointLayer = Layer.effect(ConversationObjectPorts)(
|
|
316
|
-
Effect.gen(function* () {
|
|
317
|
-
const local = yield* Effect.context<SubmissionLedger | ConversationStore>();
|
|
318
|
-
return ConversationObjectPorts.of({
|
|
319
|
-
handle: (encoded) => handleEncodedPortRequest(encoded).pipe(Effect.provide(local)),
|
|
320
|
-
});
|
|
321
|
-
}),
|
|
322
|
-
).pipe(Layer.provide(localPorts));
|
|
323
|
-
|
|
324
|
-
const routedPorts = Layer.mergeAll(
|
|
325
|
-
routedSubmissionLedgerLayer({ localConversationId: conversationId }),
|
|
326
|
-
routedConversationStoreLayer({ localConversationId: conversationId }),
|
|
327
|
-
).pipe(Layer.provide(localPorts), Layer.provide(conversationPortTransportLayer));
|
|
328
|
-
|
|
329
|
-
const runtimeConfigLayer = Layer.succeed(DurableRuntimeConfig)(
|
|
330
|
-
DurableRuntimeConfig.make({
|
|
331
|
-
deploymentId: config.deploymentId,
|
|
332
|
-
producerId,
|
|
333
|
-
settlementPollInterval: Duration.millis(config.settlementPollInterval),
|
|
334
|
-
leaseRenewalInterval: Duration.millis(config.leaseRenewalInterval),
|
|
335
|
-
abortPollInterval: Duration.millis(config.abortPollInterval),
|
|
336
|
-
}),
|
|
337
|
-
);
|
|
338
|
-
|
|
339
|
-
const runtimeFailpointLayer =
|
|
340
|
-
options.runtimeFailpoint === undefined
|
|
341
|
-
? DurableRuntimeFailpoint.layer
|
|
342
|
-
: Layer.succeed(DurableRuntimeFailpoint)({ hit: options.runtimeFailpoint(ctx) });
|
|
343
|
-
const reconcilerLayer = options.toolReconciler ?? ToolReconciler.uncertain;
|
|
344
|
-
const bindingResolverLayer = Layer.effect(AgentBindingResolver)(
|
|
345
|
-
Effect.map(
|
|
346
|
-
resolveBindings(options.bindings, { ctx, env, conversationId, producerId }),
|
|
347
|
-
(bindings) => AgentBindingResolver.fromBindings(bindings),
|
|
348
|
-
),
|
|
349
|
-
);
|
|
350
|
-
|
|
351
|
-
const base = Layer.mergeAll(
|
|
352
|
-
identityLayer,
|
|
353
|
-
cloudflareConfigLayer,
|
|
354
|
-
DurableAlarmService.layer,
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
const runtimeStack = DurableAgentRuntime.layer.pipe(
|
|
358
|
-
Layer.provideMerge(routedPorts),
|
|
359
|
-
Layer.provideMerge(cloudflareWakeSchedulerLayer),
|
|
360
|
-
Layer.provideMerge(runtimeConfigLayer),
|
|
361
|
-
Layer.provideMerge(bindingResolverLayer),
|
|
362
|
-
Layer.provide(
|
|
363
|
-
Layer.mergeAll(runtimeFailpointLayer, reconcilerLayer, BrowserCrypto.layer),
|
|
364
|
-
),
|
|
365
|
-
Layer.provideMerge(base),
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
return Layer.mergeAll(
|
|
369
|
-
runtimeStack,
|
|
370
|
-
ConversationMaintenance.layer.pipe(Layer.provide(runtimeStack)),
|
|
371
|
-
portsEndpointLayer,
|
|
372
|
-
);
|
|
373
|
-
}),
|
|
374
|
-
);
|
|
375
|
-
}
|
|
376
|
-
}
|
package/src/transport.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { ConversationPortTransport, portTransportFailure } from "@effect-agent/storage-cloudflare";
|
|
2
|
-
import { Effect, Layer } from "effect";
|
|
3
|
-
|
|
4
|
-
import { ConversationObjectNamespace } from "./bindings.ts";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* `ConversationPortTransport` over native Durable Object JS RPC (decision D-P6-3): one
|
|
8
|
-
* `portCall(envelope)` on the stub of the Object that owns the addressed Conversation
|
|
9
|
-
* (`namespace.idFromName(conversationId)` — the identity rule, plan §1.2). The envelopes are
|
|
10
|
-
* already Schema-encoded JSON, so the RPC boundary carries only structured-cloneable values;
|
|
11
|
-
* the protocol module stays transport-agnostic and fetch-with-JSON remains the documented
|
|
12
|
-
* fallback carrier.
|
|
13
|
-
*
|
|
14
|
-
* Every delivery problem — stub construction, RPC rejection, overload, deploy-in-progress —
|
|
15
|
-
* surfaces as `PortTransportError` (preserving the platform stub's own `retryable` signal
|
|
16
|
-
* when present) and NEVER as a fabricated answer: on `resolveAdmission` the routing layer
|
|
17
|
-
* turns exactly this error into `AdmissionIndeterminate` (SUB-031).
|
|
18
|
-
*/
|
|
19
|
-
export const conversationPortTransportLayer: Layer.Layer<
|
|
20
|
-
ConversationPortTransport,
|
|
21
|
-
never,
|
|
22
|
-
ConversationObjectNamespace
|
|
23
|
-
> = Layer.effect(ConversationPortTransport)(
|
|
24
|
-
Effect.gen(function* () {
|
|
25
|
-
const { namespace } = yield* ConversationObjectNamespace;
|
|
26
|
-
return ConversationPortTransport.of({
|
|
27
|
-
call: (conversationId, request) =>
|
|
28
|
-
Effect.tryPromise({
|
|
29
|
-
try: () => namespace.get(namespace.idFromName(conversationId)).portCall(request),
|
|
30
|
-
catch: (cause) => portTransportFailure(conversationId, cause),
|
|
31
|
-
}).pipe(
|
|
32
|
-
Effect.withSpan("CloudflarePortTransport.call", {
|
|
33
|
-
attributes: { conversationId },
|
|
34
|
-
}),
|
|
35
|
-
),
|
|
36
|
-
});
|
|
37
|
-
}),
|
|
38
|
-
);
|