effect-durable-agent-cloudflare 0.1.0-alpha.22 → 0.1.0-alpha.24

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.
@@ -0,0 +1,477 @@
1
+ import { _ as encodeEdaRpcDurableEvent, a as SessionOutcomeInput, d as DurableObjectTranscriptStore, i as SessionGrantRunInput, l as edaSessionRpc, n as SessionBlockInput, o as SessionScopedInput, r as SessionCommandInput, s as SessionTranscriptWindowInput, t as SessionBatchInput, u as DurableObjectTranscriptBuilder } from "./rpc-spec-B5cL83zd.js";
2
+ import { t as EDASessionController } from "./session-controller-DoUy9zR6.js";
3
+ import * as Effect from "effect/Effect";
4
+ import { durableEventEnvelope } from "effect-durable-agent/types/events/durable";
5
+ import * as Schema from "effect/Schema";
6
+ import { CommandId, RunRequestId, SequenceNumber, SessionId } from "effect-durable-agent/types/core";
7
+ import { EDATraceMetadata, makeEDATraceMetadataFromParent, makeRootEDATraceMetadata, parseEDATraceparent } from "effect-durable-agent/types/tracing";
8
+ import { EDASessionStoreError } from "effect-durable-agent/services/session-store";
9
+ import { defaultTranscriptWindowLimits, emptyTranscriptMappings, makeTranscriptDefinition } from "effect-durable-agent/transcript";
10
+ import * as Result from "effect/Result";
11
+ import { DurableObject } from "cloudflare:workers";
12
+ import { EDA_WEB_SOCKET_PING_MESSAGE, EDA_WEB_SOCKET_PONG_MESSAGE } from "effect-durable-agent/websocket";
13
+ //#region src/durable-object-alarms.ts
14
+ /**
15
+ * Shares one Durable Object alarm between owners that each keep a durable wakeup.
16
+ *
17
+ * Each owner's wakeup is a row in `_eda_alarm_wakeups`, and the platform alarm is always set to the
18
+ * earliest row, so no owner can delete or postpone another's wakeup, and after an eviction the
19
+ * alarm handler still knows which owners it fired for. An owner's view (`owner(...)`) has the
20
+ * same shape as the platform alarm API, so the keep-alive heartbeat uses it unchanged.
21
+ */
22
+ var DurableObjectAlarmScheduler = class {
23
+ storage;
24
+ now;
25
+ #tail = Promise.resolve();
26
+ constructor(storage, now = () => Date.now()) {
27
+ this.storage = storage;
28
+ this.now = now;
29
+ }
30
+ /**
31
+ * One owner's alarm, behaving like the platform alarm restricted to that owner. Like the
32
+ * platform's, it reports no alarm once its time has passed: a wakeup left behind when the
33
+ * platform gave up retrying a failed alarm must not look armed, or its owner would never re-arm.
34
+ */
35
+ owner(owner) {
36
+ return {
37
+ getAlarm: () => {
38
+ const wakeup = this.#wakeup(owner);
39
+ return wakeup === void 0 || wakeup < this.now() ? null : wakeup;
40
+ },
41
+ setAlarm: (scheduledTimeMs) => {
42
+ this.#write(owner, scheduledTimeMs);
43
+ return this.sync();
44
+ },
45
+ deleteAlarm: () => {
46
+ this.#write(owner, void 0);
47
+ return this.sync();
48
+ }
49
+ };
50
+ }
51
+ /**
52
+ * Adopt a platform alarm no owner recorded (one armed before wakeups were recorded) as the
53
+ * runtime's, so the first wakeup another owner requests cannot replace it. Call once at startup,
54
+ * before any owner writes a wakeup.
55
+ */
56
+ async adoptUnrecordedAlarm() {
57
+ if (this.#rows().length > 0) return;
58
+ const armed = await this.storage.getAlarm();
59
+ if (armed !== null && this.#rows().length === 0) this.#write("runtime", armed);
60
+ }
61
+ /**
62
+ * Record `owner`'s wakeup without touching the platform alarm, for use inside `alarm()`: the
63
+ * caller syncs once at the end, or not at all when it rethrows, which leaves the platform's own
64
+ * retry (with its backoff and cap) in force.
65
+ */
66
+ retain(owner, atMs) {
67
+ this.#write(owner, atMs);
68
+ }
69
+ /** Wake `owner` no later than `atMs`; an earlier wakeup it already holds is kept. */
70
+ request(owner, atMs) {
71
+ const current = this.#wakeup(owner);
72
+ if (current !== void 0 && current <= atMs) return this.sync();
73
+ this.#write(owner, atMs);
74
+ return this.sync();
75
+ }
76
+ /**
77
+ * Called when the platform alarm fires: the owners it fired for (every wakeup at or before now,
78
+ * and always the earliest one) and the wakeup each held. Nothing is consumed here: each owner
79
+ * `clearThrough`s its wakeup only after its work succeeds, so a handler that throws, or dies
80
+ * mid-work (eviction, deploy, a resource limit), leaves the platform's retry attributed to every
81
+ * owner it fired for. An owner's view already reports a past wakeup as no alarm, so the runtime's
82
+ * keep-alive re-arms during its work as it did with the platform alarm.
83
+ */
84
+ due(nowMs) {
85
+ const rows = this.#rows();
86
+ const earliest = rows.reduce((min, row) => Math.min(min, row.at_ms), Number.POSITIVE_INFINITY);
87
+ const threshold = Math.max(nowMs, earliest);
88
+ const due = /* @__PURE__ */ new Map();
89
+ for (const row of rows) if (row.at_ms <= threshold && isOwner(row.owner)) due.set(row.owner, row.at_ms);
90
+ return due;
91
+ }
92
+ /**
93
+ * Remove `owner`'s wakeup if it is still at or before `atMs`, once the work it fired for has
94
+ * succeeded. A later wakeup the owner re-armed during that work is kept.
95
+ */
96
+ clearThrough(owner, atMs) {
97
+ this.storage.sql.exec("DELETE FROM _eda_alarm_wakeups WHERE owner = ? AND at_ms <= ?", owner, atMs);
98
+ }
99
+ /** Point the platform alarm at the earliest wakeup, or clear it when none remains. */
100
+ sync() {
101
+ this.#tail = this.#tail.catch(() => void 0).then(async () => {
102
+ const earliest = this.storage.sql.exec("SELECT MIN(at_ms) AS at_ms FROM _eda_alarm_wakeups").one().at_ms;
103
+ if (earliest === null) {
104
+ await this.storage.deleteAlarm();
105
+ return;
106
+ }
107
+ if (await this.storage.getAlarm() !== earliest) await this.storage.setAlarm(earliest);
108
+ });
109
+ return this.#tail;
110
+ }
111
+ #rows() {
112
+ return this.storage.sql.exec("SELECT owner, at_ms FROM _eda_alarm_wakeups").toArray();
113
+ }
114
+ #wakeup(owner) {
115
+ return this.storage.sql.exec("SELECT at_ms FROM _eda_alarm_wakeups WHERE owner = ?", owner).toArray()[0]?.at_ms;
116
+ }
117
+ #write(owner, atMs) {
118
+ if (atMs === void 0) {
119
+ this.storage.sql.exec("DELETE FROM _eda_alarm_wakeups WHERE owner = ?", owner);
120
+ return;
121
+ }
122
+ this.storage.sql.exec(`INSERT INTO _eda_alarm_wakeups (owner, at_ms) VALUES (?, ?)
123
+ ON CONFLICT(owner) DO UPDATE SET at_ms = excluded.at_ms`, owner, atMs);
124
+ }
125
+ };
126
+ const isOwner = (owner) => owner === "runtime" || owner === "transcript";
127
+ //#endregion
128
+ //#region src/durable-object.ts
129
+ /** Internal Worker-to-object header selecting an app-owned WebSocket projection. */
130
+ const EDA_WEB_SOCKET_PROJECTION_HEADER = "x-eda-websocket-projection";
131
+ /**
132
+ * Upgrade query parameter selecting the socket's stream: `transcript` selects the ordered
133
+ * transcript-window stream; anything else keeps the raw event stream.
134
+ */
135
+ const EDA_WEB_SOCKET_STREAM_PARAM = "stream";
136
+ /** Slices a backfill `transcriptStatus` call may run before it returns. */
137
+ const transcriptStatusMaxSlices = 16;
138
+ /** Server bounds on one `readTranscriptWindow` RPC, whatever limits the caller asks for. */
139
+ const transcriptWindowMaxRecords = 500;
140
+ const transcriptWindowMaxBytes = 8388608;
141
+ /** Slices one builder alarm runs before rescheduling itself. */
142
+ const transcriptAlarmMaxSlices = 4;
143
+ /** Resolve a concrete EDA session Durable Object binding by domain session id. */
144
+ const getEDASessionDurableObjectByName = (namespace, sessionId) => namespace.getByName(sessionId);
145
+ /**
146
+ * Base class for raw Cloudflare Durable Object hosts of one EDA session.
147
+ *
148
+ * Concrete products should extend this class, pass provider/tool layers from
149
+ * their own constructor, and register only that subclass in Wrangler. The base
150
+ * class is deliberately not exported from `workers/app.ts` and owns no binding
151
+ * name or routing convention.
152
+ */
153
+ var EDASessionDurableObject = class extends DurableObject {
154
+ #controller;
155
+ #webSocketProjectionId;
156
+ #alarms;
157
+ #transcriptOptions;
158
+ #transcript;
159
+ constructor(ctx, env, options) {
160
+ super(ctx, env);
161
+ this.#webSocketProjectionId = options.webSocketProjection?.id;
162
+ const storage = toEDASessionStorage(this.ctx.storage);
163
+ this.#alarms = new DurableObjectAlarmScheduler(storage);
164
+ const { transcript: transcriptHostOptions, transcriptSockets, ...controllerOptions } = options;
165
+ const transcript = this.transcriptOptions(transcriptHostOptions);
166
+ this.#transcriptOptions = transcript;
167
+ this.#controller = new EDASessionController({
168
+ ...controllerOptions,
169
+ alarmStorage: this.#alarms.owner("runtime"),
170
+ background: this.ctx,
171
+ getWebSockets: () => this.ctx.getWebSockets(),
172
+ storage,
173
+ transcript,
174
+ ...transcriptSockets === void 0 ? {} : { transcriptSockets: {
175
+ ...transcriptSockets,
176
+ transcriptStore: transcriptSockets.transcriptStore ?? this.transcriptPort()
177
+ } }
178
+ });
179
+ this.ctx.setWebSocketAutoResponse(new WebSocketRequestResponsePair(EDA_WEB_SOCKET_PING_MESSAGE, EDA_WEB_SOCKET_PONG_MESSAGE));
180
+ this.ctx.blockConcurrencyWhile(async () => {
181
+ await Effect.runPromise(EDASessionController.migrate(storage));
182
+ await this.#alarms.adoptUnrecordedAlarm();
183
+ await this.objectTranscript()?.builder.start();
184
+ });
185
+ }
186
+ async fetch(request) {
187
+ if (request.headers.get("Upgrade")?.toLowerCase() !== "websocket") return new Response("Expected WebSocket upgrade.", { status: 426 });
188
+ const url = new URL(request.url);
189
+ const sessionIdRaw = url.searchParams.get("sessionId");
190
+ if (sessionIdRaw === null) return new Response("Missing sessionId.", { status: 400 });
191
+ const afterSeqRaw = url.searchParams.get("afterSeq");
192
+ const afterSeq = afterSeqRaw === null ? void 0 : Number(afterSeqRaw);
193
+ if (afterSeq !== void 0 && (!Number.isInteger(afterSeq) || afterSeq < 0)) return new Response("Invalid afterSeq.", { status: 400 });
194
+ const projectionId = request.headers.get("x-eda-websocket-projection") ?? void 0;
195
+ if (projectionId !== void 0 && projectionId !== this.#webSocketProjectionId) return new Response("Unsupported WebSocket projection.", { status: 400 });
196
+ const sessionId = this.parseSessionId(sessionIdRaw);
197
+ const trace = traceMetadataFromRequest(request);
198
+ if (url.searchParams.get("stream") === "transcript") {
199
+ if (projectionId !== void 0 || !this.#controller.supportsTranscriptWebSocket) return new Response("Unsupported transcript stream.", { status: 400 });
200
+ this.transcriptFor(sessionId);
201
+ const pair = new WebSocketPair();
202
+ this.ctx.acceptWebSocket(pair[1]);
203
+ this.#controller.acceptTranscriptWebSocket({
204
+ sessionId,
205
+ trace,
206
+ webSocket: pair[1]
207
+ });
208
+ return new Response(null, {
209
+ status: 101,
210
+ webSocket: pair[0]
211
+ });
212
+ }
213
+ const prepared = await this.#controller.prepareEventWebSocket({
214
+ ...afterSeq === void 0 ? {} : { afterSeq: SequenceNumber.make(afterSeq) },
215
+ sessionId,
216
+ trace,
217
+ ...projectionId === void 0 ? {} : { projectionId }
218
+ });
219
+ const pair = new WebSocketPair();
220
+ const client = pair[0];
221
+ const server = pair[1];
222
+ this.ctx.acceptWebSocket(server);
223
+ await this.#controller.acceptPreparedEventWebSocket({
224
+ ...prepared,
225
+ webSocket: server
226
+ });
227
+ return new Response(null, {
228
+ status: 101,
229
+ webSocket: client
230
+ });
231
+ }
232
+ async submit(raw) {
233
+ const input = Schema.decodeUnknownSync(SessionCommandInput)(raw);
234
+ const committed = await this.#controller.submit({
235
+ command: input.command,
236
+ sessionId: this.parseSessionId(input.sessionId),
237
+ trace: decodeTraceMetadata(input.trace)
238
+ });
239
+ return encodeEdaRpcCommittedDurableEvent(committed);
240
+ }
241
+ /** Reconcile lost grant replies from durable request and run facts. */
242
+ async runRequestOutcome(raw) {
243
+ const input = Schema.decodeUnknownSync(SessionOutcomeInput)(raw);
244
+ const result = await this.#controller.runRequestOutcome({
245
+ requestId: Schema.decodeUnknownSync(RunRequestId)(input.requestId),
246
+ sessionId: this.parseSessionId(input.sessionId),
247
+ trace: decodeTraceMetadata(input.trace)
248
+ });
249
+ return Schema.encodeSync(edaSessionRpc.runRequestOutcome.output)(result);
250
+ }
251
+ /** Trusted RPC only: the calling Worker owns scheduler authentication and authorization. */
252
+ async grantRun(raw) {
253
+ const input = Schema.decodeUnknownSync(SessionGrantRunInput)(raw);
254
+ const command = input.command;
255
+ const result = await this.#controller.grantRun({
256
+ command,
257
+ sessionId: this.parseSessionId(input.sessionId),
258
+ trace: decodeTraceMetadata(input.trace)
259
+ });
260
+ return Schema.encodeSync(edaSessionRpc.grantRun.output)(result);
261
+ }
262
+ async submitBatch(raw) {
263
+ const input = Schema.decodeUnknownSync(SessionBatchInput)(raw);
264
+ return (await this.#controller.submitBatch({
265
+ items: input.items,
266
+ sessionId: this.parseSessionId(input.sessionId),
267
+ trace: decodeTraceMetadata(input.trace)
268
+ })).map(encodeEdaRpcCommittedDurableEvent);
269
+ }
270
+ async submitAndBlock(raw) {
271
+ const input = Schema.decodeUnknownSync(SessionCommandInput)(raw);
272
+ const committed = await this.#controller.submitAndBlock({
273
+ command: input.command,
274
+ sessionId: this.parseSessionId(input.sessionId),
275
+ trace: decodeTraceMetadata(input.trace)
276
+ });
277
+ return Schema.encodeSync(edaSessionRpc.submitAndBlock.output)(committed);
278
+ }
279
+ async blockOnCommand(raw) {
280
+ const input = Schema.decodeUnknownSync(SessionBlockInput)(raw);
281
+ const committed = await this.#controller.blockOnCommand({
282
+ ...input.afterSeq === void 0 ? {} : { afterSeq: SequenceNumber.make(input.afterSeq) },
283
+ commandId: CommandId.make(input.commandId),
284
+ sessionId: this.parseSessionId(input.sessionId),
285
+ trace: decodeTraceMetadata(input.trace)
286
+ });
287
+ return Schema.encodeSync(edaSessionRpc.blockOnCommand.output)(committed);
288
+ }
289
+ async snapshot(raw) {
290
+ const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);
291
+ const snapshot = await this.#controller.snapshot({
292
+ sessionId: this.parseSessionId(input.sessionId),
293
+ trace: decodeTraceMetadata(input.trace)
294
+ });
295
+ return Schema.encodeSync(edaSessionRpc.snapshot.output)(snapshot);
296
+ }
297
+ async messages(raw) {
298
+ const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);
299
+ const result = await this.#controller.messages({
300
+ sessionId: this.parseSessionId(input.sessionId),
301
+ trace: decodeTraceMetadata(input.trace)
302
+ });
303
+ return Schema.encodeSync(edaSessionRpc.messages.output)(result);
304
+ }
305
+ async webSocketMessage(webSocket, message) {
306
+ await this.#controller.webSocketMessage(webSocket, message);
307
+ }
308
+ async webSocketClose(webSocket, _code, _reason, _wasClean) {
309
+ this.#controller.webSocketClose(webSocket);
310
+ }
311
+ async webSocketError(webSocket, _error) {
312
+ this.#controller.webSocketError(webSocket);
313
+ }
314
+ async destroySession(raw) {
315
+ const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);
316
+ await this.#controller.destroy({
317
+ sessionId: this.parseSessionId(input.sessionId),
318
+ trace: decodeTraceMetadata(input.trace)
319
+ });
320
+ await this.ctx.storage.deleteAlarm();
321
+ await this.ctx.storage.deleteAll();
322
+ Effect.runSync(EDASessionController.migrate(toEDASessionStorage(this.ctx.storage)));
323
+ }
324
+ /**
325
+ * Storage-only backfill entry point: advance pending transcript build work by bounded slices
326
+ * and return the transcript status. It never starts the model runtime, reducers or sinks.
327
+ */
328
+ async transcriptStatus(raw) {
329
+ const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);
330
+ const transcript = this.transcriptFor(this.parseSessionId(input.sessionId));
331
+ await transcript.builder.run(transcriptStatusMaxSlices);
332
+ return Schema.encodeSync(edaSessionRpc.transcriptStatus.output)(transcript.store.status());
333
+ }
334
+ /** Runtime-free transcript window read for SSR and CLIs. Hosts authorize the caller. */
335
+ async readTranscriptWindow(raw) {
336
+ const input = Schema.decodeUnknownSync(SessionTranscriptWindowInput)(raw);
337
+ const transcript = this.transcriptFor(this.parseSessionId(input.sessionId));
338
+ const limits = input.limits ?? defaultTranscriptWindowLimits;
339
+ const window = transcript.store.readWindow(input.selector, {
340
+ ...limits,
341
+ maxRecords: Math.min(limits.maxRecords, transcriptWindowMaxRecords),
342
+ maxBytes: Math.min(limits.maxBytes, transcriptWindowMaxBytes)
343
+ });
344
+ return Schema.encodeSync(edaSessionRpc.readTranscriptWindow.output)(Result.isSuccess(window) ? {
345
+ _tag: "Window",
346
+ window: window.success
347
+ } : {
348
+ _tag: "CursorMismatch",
349
+ message: window.failure.message
350
+ });
351
+ }
352
+ /**
353
+ * The alarm is shared by the runtime heartbeat and the transcript builder. A builder wakeup
354
+ * runs storage-only slices; the runtime runs only for its own wakeup, or for an alarm neither
355
+ * owner recorded (one armed before wakeups were recorded).
356
+ */
357
+ async alarm() {
358
+ const now = Date.now();
359
+ const due = this.#alarms.due(now);
360
+ let runtimeFailure;
361
+ if (due.has("runtime") || due.size === 0) {
362
+ const sessionId = this.sessionIdFromObjectName();
363
+ try {
364
+ await this.#controller.alarm(sessionId === void 0 ? void 0 : {
365
+ sessionId,
366
+ trace: makeRootEDATraceMetadata()
367
+ });
368
+ this.#alarms.clearThrough("runtime", due.get("runtime") ?? now);
369
+ } catch (error) {
370
+ runtimeFailure = { error };
371
+ }
372
+ }
373
+ const builderWakeup = due.get("transcript");
374
+ if (builderWakeup !== void 0) try {
375
+ const builder = this.objectTranscript()?.builder;
376
+ if (builder === void 0 ? false : await builder.runSlices(transcriptAlarmMaxSlices)) this.#alarms.retain("transcript", Date.now());
377
+ else this.#alarms.clearThrough("transcript", builderWakeup);
378
+ } catch (error) {
379
+ console.error("EDA transcript builder slice failed", error);
380
+ this.#alarms.retain("transcript", Date.now() + 3e4);
381
+ }
382
+ if (runtimeFailure !== void 0) throw runtimeFailure.error;
383
+ await this.#alarms.sync();
384
+ }
385
+ transcriptOptions(options) {
386
+ const key = options?.adoptIncarnationKey;
387
+ return {
388
+ definitions: options?.definitions ?? { current: Effect.runSync(makeTranscriptDefinition(emptyTranscriptMappings)) },
389
+ ...key === void 0 ? {} : { adoptIncarnation: {
390
+ key,
391
+ kv: this.ctx.storage.kv
392
+ } },
393
+ observer: {
394
+ onAlert: options?.onAlert ?? ((alert) => console.error("EDA transcript alert", JSON.stringify(alert))),
395
+ onPendingWork: () => {
396
+ const builder = this.objectTranscript()?.builder;
397
+ if (builder !== void 0) this.ctx.waitUntil(builder.kick());
398
+ },
399
+ onActivated: (activation) => {
400
+ this.ctx.waitUntil(this.#controller.refreshTranscriptWebSockets());
401
+ options?.onActivated?.(activation);
402
+ }
403
+ }
404
+ };
405
+ }
406
+ /** This object's transcript store as the port transcript sockets read, resolved per call. */
407
+ transcriptPort() {
408
+ const port = () => this.objectTranscript()?.store.port;
409
+ const unbound = () => Effect.fail(new EDASessionStoreError({ message: "EDA transcript read before the session was named" }));
410
+ return {
411
+ readTranscriptWindow: (selector, limits) => Effect.suspend(() => port()?.readTranscriptWindow(selector, limits) ?? unbound()),
412
+ readTranscriptMeta: Effect.suspend(() => port()?.readTranscriptMeta ?? unbound())
413
+ };
414
+ }
415
+ /** The transcript service of this object's session, created on first use. */
416
+ transcriptFor(sessionId) {
417
+ if (this.#transcript !== void 0) {
418
+ if (this.#transcript.sessionId !== sessionId) throw new Error(`EDA transcript is scoped to session ${this.#transcript.sessionId}; received ${sessionId}`);
419
+ return this.#transcript;
420
+ }
421
+ const store = new DurableObjectTranscriptStore({
422
+ sessionId,
423
+ storage: toEDASessionStorage(this.ctx.storage),
424
+ transcript: this.#transcriptOptions
425
+ });
426
+ const builder = new DurableObjectTranscriptBuilder(store, () => this.#alarms.request("transcript", Date.now()));
427
+ this.#transcript = {
428
+ sessionId,
429
+ store,
430
+ builder
431
+ };
432
+ return this.#transcript;
433
+ }
434
+ /** The transcript service when the object is named by a valid session id. */
435
+ objectTranscript() {
436
+ if (this.#transcript !== void 0) return this.#transcript;
437
+ const name = this.ctx.id.name;
438
+ return name !== void 0 && Schema.is(SessionId)(name) ? this.transcriptFor(SessionId.make(name)) : void 0;
439
+ }
440
+ parseSessionId(input) {
441
+ const sessionId = SessionId.make(input);
442
+ const objectName = this.ctx.id.name;
443
+ if (objectName !== void 0 && objectName !== sessionId) throw new Error(`EDA Durable Object name ${objectName} cannot serve session ${sessionId}`);
444
+ return sessionId;
445
+ }
446
+ sessionIdFromObjectName() {
447
+ return this.ctx.id.name === void 0 ? void 0 : SessionId.make(this.ctx.id.name);
448
+ }
449
+ };
450
+ const toEDASessionStorage = (storage) => {
451
+ return storage;
452
+ };
453
+ const decodeTraceMetadata = (input) => Schema.decodeUnknownSync(EDATraceMetadata)(input);
454
+ const traceMetadataFromRequest = (request) => {
455
+ const parent = parseEDATraceparent(request.headers.get("traceparent"), request.headers.get("tracestate"));
456
+ return parent === null ? makeRootEDATraceMetadata() : makeEDATraceMetadataFromParent(parent);
457
+ };
458
+ /** Convenience config constructor for subclasses that need only provider/model ids. */
459
+ const edaRuntimeConfig = (input) => ({
460
+ modelSelection: {
461
+ modelId: input.modelId,
462
+ provider: input.provider
463
+ },
464
+ ...input.maxToolCallsPerRun === void 0 ? {} : { maxToolCallsPerRun: input.maxToolCallsPerRun },
465
+ ...input.systemPrompt === void 0 ? {} : { systemPrompt: input.systemPrompt }
466
+ });
467
+ /** Encode committed events into the existing structured-clone envelope. */
468
+ const encodeEdaRpcCommittedDurableEvent = (entry) => ({
469
+ position: entry.position,
470
+ event: encodeEdaRpcDurableEvent(durableEventEnvelope(entry.event))
471
+ });
472
+ /** Encode query snapshots without asserting that encoded command values are decoded classes. */
473
+ const encodeEdaRpcSessionSnapshot = Schema.encodeSync(edaSessionRpc.snapshot.output);
474
+ //#endregion
475
+ export { encodeEdaRpcCommittedDurableEvent as a, DurableObjectAlarmScheduler as c, edaRuntimeConfig as i, EDA_WEB_SOCKET_PROJECTION_HEADER as n, encodeEdaRpcSessionSnapshot as o, EDA_WEB_SOCKET_STREAM_PARAM as r, getEDASessionDurableObjectByName as s, EDASessionDurableObject as t };
476
+
477
+ //# sourceMappingURL=durable-object-BZJM3RyV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"durable-object-BZJM3RyV.js","names":["#wakeup","#write","#rows","#tail","#controller","#webSocketProjectionId","#alarms","#transcriptOptions","#transcript"],"sources":["../src/durable-object-alarms.ts","../src/durable-object.ts"],"sourcesContent":["import type { DurableObjectAlarmStorage } from \"./durable-object-keepalive\";\nimport type { DurableObjectSessionStorage } from \"./durable-object-storage\";\n\n/**\n * The independent owners of a session object's single platform alarm.\n *\n * - `runtime`: the keep-alive heartbeat and run-scheduling redelivery; its wakeup builds the model\n * runtime.\n * - `transcript`: the transcript builder; its wakeup runs storage-only slices and must never\n * build the model runtime.\n */\nexport type DurableObjectAlarmOwner = \"runtime\" | \"transcript\";\n\n/**\n * Shares one Durable Object alarm between owners that each keep a durable wakeup.\n *\n * Each owner's wakeup is a row in `_eda_alarm_wakeups`, and the platform alarm is always set to the\n * earliest row, so no owner can delete or postpone another's wakeup, and after an eviction the\n * alarm handler still knows which owners it fired for. An owner's view (`owner(...)`) has the\n * same shape as the platform alarm API, so the keep-alive heartbeat uses it unchanged.\n */\nexport class DurableObjectAlarmScheduler {\n #tail: Promise<void> = Promise.resolve();\n\n constructor(\n private readonly storage: DurableObjectSessionStorage & DurableObjectAlarmStorage,\n private readonly now: () => number = () => Date.now(),\n ) {}\n\n /**\n * One owner's alarm, behaving like the platform alarm restricted to that owner. Like the\n * platform's, it reports no alarm once its time has passed: a wakeup left behind when the\n * platform gave up retrying a failed alarm must not look armed, or its owner would never re-arm.\n */\n owner(owner: DurableObjectAlarmOwner): DurableObjectAlarmStorage {\n return {\n getAlarm: () => {\n const wakeup = this.#wakeup(owner);\n return wakeup === undefined || wakeup < this.now() ? null : wakeup;\n },\n setAlarm: (scheduledTimeMs) => {\n this.#write(owner, scheduledTimeMs);\n return this.sync();\n },\n deleteAlarm: () => {\n this.#write(owner, undefined);\n return this.sync();\n },\n };\n }\n\n /**\n * Adopt a platform alarm no owner recorded (one armed before wakeups were recorded) as the\n * runtime's, so the first wakeup another owner requests cannot replace it. Call once at startup,\n * before any owner writes a wakeup.\n */\n async adoptUnrecordedAlarm(): Promise<void> {\n if (this.#rows().length > 0) return;\n const armed = await this.storage.getAlarm();\n if (armed !== null && this.#rows().length === 0) this.#write(\"runtime\", armed);\n }\n\n /**\n * Record `owner`'s wakeup without touching the platform alarm, for use inside `alarm()`: the\n * caller syncs once at the end, or not at all when it rethrows, which leaves the platform's own\n * retry (with its backoff and cap) in force.\n */\n retain(owner: DurableObjectAlarmOwner, atMs: number): void {\n this.#write(owner, atMs);\n }\n\n /** Wake `owner` no later than `atMs`; an earlier wakeup it already holds is kept. */\n request(owner: DurableObjectAlarmOwner, atMs: number): Promise<void> {\n const current = this.#wakeup(owner);\n if (current !== undefined && current <= atMs) return this.sync();\n this.#write(owner, atMs);\n return this.sync();\n }\n\n /**\n * Called when the platform alarm fires: the owners it fired for (every wakeup at or before now,\n * and always the earliest one) and the wakeup each held. Nothing is consumed here: each owner\n * `clearThrough`s its wakeup only after its work succeeds, so a handler that throws, or dies\n * mid-work (eviction, deploy, a resource limit), leaves the platform's retry attributed to every\n * owner it fired for. An owner's view already reports a past wakeup as no alarm, so the runtime's\n * keep-alive re-arms during its work as it did with the platform alarm.\n */\n due(nowMs: number): ReadonlyMap<DurableObjectAlarmOwner, number> {\n const rows = this.#rows();\n const earliest = rows.reduce((min, row) => Math.min(min, row.at_ms), Number.POSITIVE_INFINITY);\n const threshold = Math.max(nowMs, earliest);\n const due = new Map<DurableObjectAlarmOwner, number>();\n for (const row of rows) {\n if (row.at_ms <= threshold && isOwner(row.owner)) due.set(row.owner, row.at_ms);\n }\n return due;\n }\n\n /**\n * Remove `owner`'s wakeup if it is still at or before `atMs`, once the work it fired for has\n * succeeded. A later wakeup the owner re-armed during that work is kept.\n */\n clearThrough(owner: DurableObjectAlarmOwner, atMs: number): void {\n this.storage.sql.exec(\n \"DELETE FROM _eda_alarm_wakeups WHERE owner = ? AND at_ms <= ?\",\n owner,\n atMs,\n );\n }\n\n /** Point the platform alarm at the earliest wakeup, or clear it when none remains. */\n sync(): Promise<void> {\n this.#tail = this.#tail\n .catch(() => undefined)\n .then(async () => {\n const earliest = this.storage.sql\n .exec<{ readonly at_ms: number | null }>(\n \"SELECT MIN(at_ms) AS at_ms FROM _eda_alarm_wakeups\",\n )\n .one().at_ms;\n if (earliest === null) {\n await this.storage.deleteAlarm();\n return;\n }\n if ((await this.storage.getAlarm()) !== earliest) {\n await this.storage.setAlarm(earliest);\n }\n });\n return this.#tail;\n }\n\n #rows(): ReadonlyArray<{ readonly owner: string; readonly at_ms: number }> {\n return this.storage.sql\n .exec<{ readonly owner: string; readonly at_ms: number }>(\n \"SELECT owner, at_ms FROM _eda_alarm_wakeups\",\n )\n .toArray();\n }\n\n #wakeup(owner: DurableObjectAlarmOwner): number | undefined {\n return this.storage.sql\n .exec<{ readonly at_ms: number }>(\n \"SELECT at_ms FROM _eda_alarm_wakeups WHERE owner = ?\",\n owner,\n )\n .toArray()[0]?.at_ms;\n }\n\n #write(owner: DurableObjectAlarmOwner, atMs: number | undefined): void {\n if (atMs === undefined) {\n this.storage.sql.exec(\"DELETE FROM _eda_alarm_wakeups WHERE owner = ?\", owner);\n return;\n }\n this.storage.sql.exec(\n `INSERT INTO _eda_alarm_wakeups (owner, at_ms) VALUES (?, ?)\n ON CONFLICT(owner) DO UPDATE SET at_ms = excluded.at_ms`,\n owner,\n atMs,\n );\n }\n}\n\nconst isOwner = (owner: string): owner is DurableObjectAlarmOwner =>\n owner === \"runtime\" || owner === \"transcript\";\n","import type { CommittedDurableEvent } from \"effect-durable-agent/services/session-store\";\nimport { durableEventEnvelope } from \"effect-durable-agent/types/events/durable\";\nimport { encodeEdaRpcDurableEvent } from \"./rpc-codec\";\nimport {\n SessionScopedInput,\n SessionTranscriptWindowInput,\n SessionCommandInput,\n SessionGrantRunInput,\n SessionBatchInput,\n SessionBlockInput,\n SessionOutcomeInput,\n edaSessionRpc,\n} from \"./rpc-spec\";\nimport { DurableObject } from \"cloudflare:workers\";\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\n\nimport type { EDARuntimeConfig } from \"effect-durable-agent/services/runtime\";\nimport {\n CommandId,\n RunRequestId,\n SequenceNumber,\n SessionId,\n} from \"effect-durable-agent/types/core\";\nimport {\n EDATraceMetadata,\n makeEDATraceMetadataFromParent,\n makeRootEDATraceMetadata,\n parseEDATraceparent,\n} from \"effect-durable-agent/types/tracing\";\nimport {\n EDASessionController,\n type EDASessionControllerOptions,\n type EDASessionDurableObjectStorage,\n} from \"./session-controller\";\nimport {\n EDA_WEB_SOCKET_PING_MESSAGE,\n EDA_WEB_SOCKET_PONG_MESSAGE,\n} from \"effect-durable-agent/websocket\";\nimport * as Result from \"effect/Result\";\nimport {\n defaultTranscriptWindowLimits,\n emptyTranscriptMappings,\n makeTranscriptDefinition,\n type EDATranscriptStoreShape,\n type TranscriptMaintenanceConfig,\n} from \"effect-durable-agent/transcript\";\nimport { DurableObjectAlarmScheduler } from \"./durable-object-alarms\";\nimport type { EDATranscriptSocketOptions } from \"./websocket/transcript-sockets\";\nimport { EDASessionStoreError } from \"effect-durable-agent/services/session-store\";\nimport {\n DurableObjectTranscriptBuilder,\n DurableObjectTranscriptStore,\n} from \"./durable-object-transcript\";\nimport type {\n DurableObjectTranscriptObserver,\n DurableObjectTranscriptOptions,\n TranscriptAlert,\n} from \"./durable-object-transcript-maintenance\";\n\nexport type { EDAWebSocketProjection } from \"./websocket/projection\";\n/** Internal Worker-to-object header selecting an app-owned WebSocket projection. */\nexport const EDA_WEB_SOCKET_PROJECTION_HEADER = \"x-eda-websocket-projection\";\n\n/**\n * Upgrade query parameter selecting the socket's stream: `transcript` selects the ordered\n * transcript-window stream; anything else keeps the raw event stream.\n */\nexport const EDA_WEB_SOCKET_STREAM_PARAM = \"stream\";\n\n/** Encoded session RPC inputs, decoded before invoking the controller. */\nexport type EDASessionCommandRpcInput = typeof SessionCommandInput.Encoded;\nexport type EDASessionGrantRunRpcInput = typeof SessionGrantRunInput.Encoded;\nexport type EDASessionSubmitBatchRpcInput = typeof SessionBatchInput.Encoded;\nexport type EDASessionScopedRpcInput = typeof SessionScopedInput.Encoded;\nexport type EDASessionEventsRpcInput = EDASessionScopedRpcInput & { readonly afterSeq?: number };\nexport type EDASessionBlockOnCommandRpcInput = typeof SessionBlockInput.Encoded;\nexport type EDASessionRunRequestOutcomeRpcInput = typeof SessionOutcomeInput.Encoded;\n\n/** EDA RPC methods required by the session namespace helper. */\nexport interface EDASessionRpcSurface {\n readonly runRequestOutcome: (\n input: EDASessionRunRequestOutcomeRpcInput,\n ) => Promise<typeof edaSessionRpc.runRequestOutcome.output.Encoded>;\n readonly grantRun: (\n input: EDASessionGrantRunRpcInput,\n ) => Promise<typeof edaSessionRpc.grantRun.output.Encoded>;\n readonly submit: (\n input: EDASessionCommandRpcInput,\n ) => Promise<typeof edaSessionRpc.submit.output.Encoded>;\n readonly submitBatch: (\n input: EDASessionSubmitBatchRpcInput,\n ) => Promise<typeof edaSessionRpc.submitBatch.output.Encoded>;\n readonly submitAndBlock: (\n input: EDASessionCommandRpcInput,\n ) => Promise<typeof edaSessionRpc.submitAndBlock.output.Encoded>;\n readonly blockOnCommand: (\n input: EDASessionBlockOnCommandRpcInput,\n ) => Promise<typeof edaSessionRpc.blockOnCommand.output.Encoded>;\n readonly snapshot: (\n input: EDASessionScopedRpcInput,\n ) => Promise<typeof edaSessionRpc.snapshot.output.Encoded>;\n readonly messages: (\n input: EDASessionScopedRpcInput,\n ) => Promise<typeof edaSessionRpc.messages.output.Encoded>;\n readonly destroySession: (\n input: EDASessionScopedRpcInput,\n ) => Promise<typeof edaSessionRpc.destroySession.output.Encoded>;\n readonly transcriptStatus: (\n input: EDASessionScopedRpcInput,\n ) => Promise<typeof edaSessionRpc.transcriptStatus.output.Encoded>;\n readonly readTranscriptWindow: (\n input: typeof SessionTranscriptWindowInput.Encoded,\n ) => Promise<typeof edaSessionRpc.readTranscriptWindow.output.Encoded>;\n}\n\n/** Host transcript configuration of a session Durable Object. */\nexport interface EDASessionTranscriptOptions {\n /**\n * The transcript definitions this release carries. Defaults to the definition with no host\n * mappings. A host changing its mappings ships `current` = new, `previous` = old, then runs\n * its backfill through `transcriptStatus` (see `docs/transcript-history.md` §7).\n */\n readonly definitions?: TranscriptMaintenanceConfig;\n /**\n * Adopt the host's existing log incarnation from this `ctx.storage.kv` key (Gia:\n * `gia.log_incarnation`). Without it the adapter mints its own.\n */\n readonly adoptIncarnationKey?: string;\n /** Alerts (frozen versions, missed sessions). Defaults to `console.error`. */\n readonly onAlert?: (alert: TranscriptAlert) => void;\n /** A rebuilt version became active. */\n readonly onActivated?: DurableObjectTranscriptObserver[\"onActivated\"];\n}\n\n/** Constructor options for concrete app subclasses of the EDA Durable Object base. */\nexport type EDASessionDurableObjectOptions<ProjectionState extends object = never> = Omit<\n EDASessionControllerOptions<ProjectionState>,\n \"alarmStorage\" | \"background\" | \"getWebSockets\" | \"storage\" | \"transcript\" | \"transcriptSockets\"\n> & {\n readonly transcript?: EDASessionTranscriptOptions;\n /**\n * Serve transcript-window sockets (`?stream=transcript`). `transcriptStore` defaults to this\n * object's own runtime-free Durable Object transcript store.\n */\n readonly transcriptSockets?: Omit<EDATranscriptSocketOptions, \"transcriptStore\"> & {\n readonly transcriptStore?: EDATranscriptSocketOptions[\"transcriptStore\"];\n };\n};\n\n/** Slices a backfill `transcriptStatus` call may run before it returns. */\nconst transcriptStatusMaxSlices = 16;\n/** Server bounds on one `readTranscriptWindow` RPC, whatever limits the caller asks for. */\nconst transcriptWindowMaxRecords = 500;\nconst transcriptWindowMaxBytes = 8 * 1_048_576;\n/** Slices one builder alarm runs before rescheduling itself. */\nconst transcriptAlarmMaxSlices = 4;\n\n/** Resolve a concrete EDA session Durable Object binding by domain session id. */\nexport const getEDASessionDurableObjectByName = <\n T extends Rpc.DurableObjectBranded & EDASessionRpcSurface,\n>(\n namespace: DurableObjectNamespace<T>,\n sessionId: string,\n): DurableObjectStub<T> => namespace.getByName(sessionId);\n\n/**\n * Base class for raw Cloudflare Durable Object hosts of one EDA session.\n *\n * Concrete products should extend this class, pass provider/tool layers from\n * their own constructor, and register only that subclass in Wrangler. The base\n * class is deliberately not exported from `workers/app.ts` and owns no binding\n * name or routing convention.\n */\nexport abstract class EDASessionDurableObject<\n EnvType extends object = object,\n ProjectionState extends object = never,\n> extends DurableObject<EnvType> {\n readonly #controller: EDASessionController<ProjectionState>;\n readonly #webSocketProjectionId: string | undefined;\n readonly #alarms: DurableObjectAlarmScheduler;\n readonly #transcriptOptions: DurableObjectTranscriptOptions;\n #transcript:\n | {\n readonly sessionId: SessionId;\n readonly store: DurableObjectTranscriptStore;\n readonly builder: DurableObjectTranscriptBuilder;\n }\n | undefined;\n\n protected constructor(\n ctx: DurableObjectState,\n env: EnvType,\n options: EDASessionDurableObjectOptions<ProjectionState>,\n ) {\n super(ctx, env);\n this.#webSocketProjectionId = options.webSocketProjection?.id;\n const storage = toEDASessionStorage(this.ctx.storage);\n this.#alarms = new DurableObjectAlarmScheduler(storage);\n const { transcript: transcriptHostOptions, transcriptSockets, ...controllerOptions } = options;\n const transcript = this.transcriptOptions(transcriptHostOptions);\n this.#transcriptOptions = transcript;\n this.#controller = new EDASessionController({\n ...controllerOptions,\n alarmStorage: this.#alarms.owner(\"runtime\"),\n background: this.ctx,\n getWebSockets: () => this.ctx.getWebSockets(),\n storage,\n transcript,\n ...(transcriptSockets === undefined\n ? {}\n : {\n transcriptSockets: {\n ...transcriptSockets,\n transcriptStore: transcriptSockets.transcriptStore ?? this.transcriptPort(),\n },\n }),\n });\n\n // Answer client liveness pings at the runtime layer so idle sockets never\n // wake a hibernated object.\n this.ctx.setWebSocketAutoResponse(\n new WebSocketRequestResponsePair(EDA_WEB_SOCKET_PING_MESSAGE, EDA_WEB_SOCKET_PONG_MESSAGE),\n );\n\n this.ctx.blockConcurrencyWhile(async () => {\n await Effect.runPromise(EDASessionController.migrate(storage));\n // Keep an alarm armed by an earlier release for the runtime, then resume any builder\n // work an earlier instance left (or a new release created).\n await this.#alarms.adoptUnrecordedAlarm();\n await this.objectTranscript()?.builder.start();\n });\n }\n\n async fetch(request: Request): Promise<Response> {\n const upgrade = request.headers.get(\"Upgrade\");\n if (upgrade?.toLowerCase() !== \"websocket\") {\n return new Response(\"Expected WebSocket upgrade.\", { status: 426 });\n }\n\n const url = new URL(request.url);\n const sessionIdRaw = url.searchParams.get(\"sessionId\");\n if (sessionIdRaw === null) {\n return new Response(\"Missing sessionId.\", { status: 400 });\n }\n const afterSeqRaw = url.searchParams.get(\"afterSeq\");\n const afterSeq = afterSeqRaw === null ? undefined : Number(afterSeqRaw);\n if (afterSeq !== undefined && (!Number.isInteger(afterSeq) || afterSeq < 0)) {\n return new Response(\"Invalid afterSeq.\", { status: 400 });\n }\n const projectionId = request.headers.get(EDA_WEB_SOCKET_PROJECTION_HEADER) ?? undefined;\n if (projectionId !== undefined && projectionId !== this.#webSocketProjectionId) {\n return new Response(\"Unsupported WebSocket projection.\", { status: 400 });\n }\n\n const sessionId = this.parseSessionId(sessionIdRaw);\n const trace = traceMetadataFromRequest(request);\n\n if (url.searchParams.get(EDA_WEB_SOCKET_STREAM_PARAM) === \"transcript\") {\n if (projectionId !== undefined || !this.#controller.supportsTranscriptWebSocket) {\n return new Response(\"Unsupported transcript stream.\", { status: 400 });\n }\n this.transcriptFor(sessionId);\n const pair = new WebSocketPair();\n this.ctx.acceptWebSocket(pair[1]);\n this.#controller.acceptTranscriptWebSocket({ sessionId, trace, webSocket: pair[1] });\n return new Response(null, { status: 101, webSocket: pair[0] });\n }\n\n const prepared = await this.#controller.prepareEventWebSocket({\n ...(afterSeq === undefined ? {} : { afterSeq: SequenceNumber.make(afterSeq) }),\n sessionId,\n trace,\n ...(projectionId === undefined ? {} : { projectionId }),\n });\n\n const pair = new WebSocketPair();\n const client = pair[0];\n const server = pair[1];\n this.ctx.acceptWebSocket(server);\n await this.#controller.acceptPreparedEventWebSocket({\n ...prepared,\n webSocket: server,\n });\n return new Response(null, { status: 101, webSocket: client });\n }\n\n async submit(\n raw: typeof SessionCommandInput.Encoded,\n ): Promise<typeof edaSessionRpc.submit.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionCommandInput)(raw);\n const committed = await this.#controller.submit({\n command: input.command,\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return encodeEdaRpcCommittedDurableEvent(committed);\n }\n\n /** Reconcile lost grant replies from durable request and run facts. */\n async runRequestOutcome(\n raw: typeof SessionOutcomeInput.Encoded,\n ): Promise<typeof edaSessionRpc.runRequestOutcome.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionOutcomeInput)(raw);\n const result = await this.#controller.runRequestOutcome({\n requestId: Schema.decodeUnknownSync(RunRequestId)(input.requestId),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.runRequestOutcome.output)(result);\n }\n\n /** Trusted RPC only: the calling Worker owns scheduler authentication and authorization. */\n async grantRun(\n raw: typeof SessionGrantRunInput.Encoded,\n ): Promise<typeof edaSessionRpc.grantRun.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionGrantRunInput)(raw);\n const command = input.command;\n const result = await this.#controller.grantRun({\n command,\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.grantRun.output)(result);\n }\n\n async submitBatch(\n raw: typeof SessionBatchInput.Encoded,\n ): Promise<typeof edaSessionRpc.submitBatch.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionBatchInput)(raw);\n const committed = await this.#controller.submitBatch({\n items: input.items,\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return committed.map(encodeEdaRpcCommittedDurableEvent);\n }\n\n async submitAndBlock(\n raw: typeof SessionCommandInput.Encoded,\n ): Promise<typeof edaSessionRpc.submitAndBlock.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionCommandInput)(raw);\n const committed = await this.#controller.submitAndBlock({\n command: input.command,\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.submitAndBlock.output)(committed);\n }\n\n async blockOnCommand(\n raw: typeof SessionBlockInput.Encoded,\n ): Promise<typeof edaSessionRpc.blockOnCommand.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionBlockInput)(raw);\n const committed = await this.#controller.blockOnCommand({\n ...(input.afterSeq === undefined ? {} : { afterSeq: SequenceNumber.make(input.afterSeq) }),\n commandId: CommandId.make(input.commandId),\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.blockOnCommand.output)(committed);\n }\n\n async snapshot(\n raw: typeof SessionScopedInput.Encoded,\n ): Promise<typeof edaSessionRpc.snapshot.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);\n const snapshot = await this.#controller.snapshot({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.snapshot.output)(snapshot);\n }\n\n async messages(\n raw: typeof SessionScopedInput.Encoded,\n ): Promise<typeof edaSessionRpc.messages.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);\n const result = await this.#controller.messages({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n return Schema.encodeSync(edaSessionRpc.messages.output)(result);\n }\n\n async webSocketMessage(webSocket: WebSocket, message: string | ArrayBuffer): Promise<void> {\n await this.#controller.webSocketMessage(webSocket, message);\n }\n\n async webSocketClose(\n webSocket: WebSocket,\n _code: number,\n _reason: string,\n _wasClean: boolean,\n ): Promise<void> {\n this.#controller.webSocketClose(webSocket);\n }\n\n async webSocketError(webSocket: WebSocket, _error: unknown): Promise<void> {\n this.#controller.webSocketError(webSocket);\n }\n\n async destroySession(\n raw: typeof SessionScopedInput.Encoded,\n ): Promise<typeof edaSessionRpc.destroySession.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);\n await this.#controller.destroy({\n sessionId: this.parseSessionId(input.sessionId),\n trace: decodeTraceMetadata(input.trace),\n });\n await this.ctx.storage.deleteAlarm();\n await this.ctx.storage.deleteAll();\n // The wiped storage is a brand-new log: recreate the tables storage-only entry points read,\n // synchronously, so no other work observes the object without them.\n Effect.runSync(EDASessionController.migrate(toEDASessionStorage(this.ctx.storage)));\n }\n\n /**\n * Storage-only backfill entry point: advance pending transcript build work by bounded slices\n * and return the transcript status. It never starts the model runtime, reducers or sinks.\n */\n async transcriptStatus(\n raw: typeof SessionScopedInput.Encoded,\n ): Promise<typeof edaSessionRpc.transcriptStatus.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionScopedInput)(raw);\n const transcript = this.transcriptFor(this.parseSessionId(input.sessionId));\n await transcript.builder.run(transcriptStatusMaxSlices);\n return Schema.encodeSync(edaSessionRpc.transcriptStatus.output)(transcript.store.status());\n }\n\n /** Runtime-free transcript window read for SSR and CLIs. Hosts authorize the caller. */\n async readTranscriptWindow(\n raw: typeof SessionTranscriptWindowInput.Encoded,\n ): Promise<typeof edaSessionRpc.readTranscriptWindow.output.Encoded> {\n const input = Schema.decodeUnknownSync(SessionTranscriptWindowInput)(raw);\n const transcript = this.transcriptFor(this.parseSessionId(input.sessionId));\n const limits = input.limits ?? defaultTranscriptWindowLimits;\n const window = transcript.store.readWindow(input.selector, {\n ...limits,\n maxRecords: Math.min(limits.maxRecords, transcriptWindowMaxRecords),\n maxBytes: Math.min(limits.maxBytes, transcriptWindowMaxBytes),\n });\n return Schema.encodeSync(edaSessionRpc.readTranscriptWindow.output)(\n Result.isSuccess(window)\n ? { _tag: \"Window\", window: window.success }\n : { _tag: \"CursorMismatch\", message: window.failure.message },\n );\n }\n\n /**\n * The alarm is shared by the runtime heartbeat and the transcript builder. A builder wakeup\n * runs storage-only slices; the runtime runs only for its own wakeup, or for an alarm neither\n * owner recorded (one armed before wakeups were recorded).\n */\n async alarm(): Promise<void> {\n const now = Date.now();\n const due = this.#alarms.due(now);\n let runtimeFailure: { readonly error: unknown } | undefined;\n if (due.has(\"runtime\") || due.size === 0) {\n const sessionId = this.sessionIdFromObjectName();\n try {\n await this.#controller.alarm(\n sessionId === undefined ? undefined : { sessionId, trace: makeRootEDATraceMetadata() },\n );\n this.#alarms.clearThrough(\"runtime\", due.get(\"runtime\") ?? now);\n } catch (error) {\n runtimeFailure = { error };\n }\n }\n const builderWakeup = due.get(\"transcript\");\n if (builderWakeup !== undefined) {\n try {\n const builder = this.objectTranscript()?.builder;\n const more =\n builder === undefined ? false : await builder.runSlices(transcriptAlarmMaxSlices);\n if (more) this.#alarms.retain(\"transcript\", Date.now());\n else this.#alarms.clearThrough(\"transcript\", builderWakeup);\n } catch (error) {\n console.error(\"EDA transcript builder slice failed\", error);\n this.#alarms.retain(\"transcript\", Date.now() + 30_000);\n }\n }\n // A failed runtime alarm leaves the platform alarm alone: the platform's retry (with its\n // backoff and cap) runs it again, with every wakeup it fired for still recorded.\n if (runtimeFailure !== undefined) throw runtimeFailure.error;\n await this.#alarms.sync();\n }\n\n private transcriptOptions(\n options: EDASessionTranscriptOptions | undefined,\n ): DurableObjectTranscriptOptions {\n const key = options?.adoptIncarnationKey;\n return {\n definitions: options?.definitions ?? {\n current: Effect.runSync(makeTranscriptDefinition(emptyTranscriptMappings)),\n },\n ...(key === undefined ? {} : { adoptIncarnation: { key, kv: this.ctx.storage.kv } }),\n observer: {\n onAlert:\n options?.onAlert ??\n ((alert) => console.error(\"EDA transcript alert\", JSON.stringify(alert))),\n onPendingWork: () => {\n const builder = this.objectTranscript()?.builder;\n if (builder !== undefined) this.ctx.waitUntil(builder.kick());\n },\n onActivated: (activation) => {\n // Connected transcript sockets get one complete replacement in the new version.\n this.ctx.waitUntil(this.#controller.refreshTranscriptWebSockets());\n options?.onActivated?.(activation);\n },\n },\n };\n }\n\n /** This object's transcript store as the port transcript sockets read, resolved per call. */\n private transcriptPort(): EDATranscriptStoreShape {\n const port = () => this.objectTranscript()?.store.port;\n const unbound = () =>\n Effect.fail(\n new EDASessionStoreError({ message: \"EDA transcript read before the session was named\" }),\n );\n return {\n readTranscriptWindow: (selector, limits) =>\n Effect.suspend(() => port()?.readTranscriptWindow(selector, limits) ?? unbound()),\n readTranscriptMeta: Effect.suspend(() => port()?.readTranscriptMeta ?? unbound()),\n };\n }\n\n /** The transcript service of this object's session, created on first use. */\n private transcriptFor(sessionId: SessionId) {\n if (this.#transcript !== undefined) {\n if (this.#transcript.sessionId !== sessionId) {\n throw new Error(\n `EDA transcript is scoped to session ${this.#transcript.sessionId}; received ${sessionId}`,\n );\n }\n return this.#transcript;\n }\n const store = new DurableObjectTranscriptStore({\n sessionId,\n storage: toEDASessionStorage(this.ctx.storage),\n transcript: this.#transcriptOptions,\n });\n const builder = new DurableObjectTranscriptBuilder(store, () =>\n this.#alarms.request(\"transcript\", Date.now()),\n );\n this.#transcript = { sessionId, store, builder };\n return this.#transcript;\n }\n\n /** The transcript service when the object is named by a valid session id. */\n private objectTranscript() {\n if (this.#transcript !== undefined) return this.#transcript;\n const name = this.ctx.id.name;\n return name !== undefined && Schema.is(SessionId)(name)\n ? this.transcriptFor(SessionId.make(name))\n : undefined;\n }\n\n private parseSessionId(input: string): SessionId {\n const sessionId = SessionId.make(input);\n const objectName = this.ctx.id.name;\n if (objectName !== undefined && objectName !== sessionId) {\n throw new Error(`EDA Durable Object name ${objectName} cannot serve session ${sessionId}`);\n }\n return sessionId;\n }\n\n private sessionIdFromObjectName(): SessionId | undefined {\n return this.ctx.id.name === undefined ? undefined : SessionId.make(this.ctx.id.name);\n }\n}\n\nconst toEDASessionStorage = (storage: DurableObjectStorage): EDASessionDurableObjectStorage => {\n // SAFETY: the adapter interface is the exact SQL, transaction, and alarm subset\n // of DurableObjectStorage; its looser row generic also supports test implementations.\n return storage as EDASessionDurableObjectStorage;\n};\n\nconst decodeTraceMetadata = (input: unknown): EDATraceMetadata =>\n Schema.decodeUnknownSync(EDATraceMetadata)(input);\n\nconst traceMetadataFromRequest = (request: Request): EDATraceMetadata => {\n const parent = parseEDATraceparent(\n request.headers.get(\"traceparent\"),\n request.headers.get(\"tracestate\"),\n );\n return parent === null ? makeRootEDATraceMetadata() : makeEDATraceMetadataFromParent(parent);\n};\n\n/** Convenience config constructor for subclasses that need only provider/model ids. */\nexport const edaRuntimeConfig = (input: {\n readonly maxToolCallsPerRun?: number;\n readonly modelId: string;\n readonly provider: string;\n readonly systemPrompt?: string;\n}): EDARuntimeConfig => ({\n modelSelection: { modelId: input.modelId, provider: input.provider },\n ...(input.maxToolCallsPerRun === undefined\n ? {}\n : { maxToolCallsPerRun: input.maxToolCallsPerRun }),\n ...(input.systemPrompt === undefined ? {} : { systemPrompt: input.systemPrompt }),\n});\n\n/** Encode committed events into the existing structured-clone envelope. */\nexport const encodeEdaRpcCommittedDurableEvent = (\n entry: CommittedDurableEvent,\n): typeof edaSessionRpc.submit.output.Encoded => ({\n position: entry.position,\n event: encodeEdaRpcDurableEvent(durableEventEnvelope(entry.event)),\n});\n/** Encode query snapshots without asserting that encoded command values are decoded classes. */\nexport const encodeEdaRpcSessionSnapshot = Schema.encodeSync(edaSessionRpc.snapshot.output);\n"],"mappings":"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"}