effect-durable-agent-cloudflare 0.1.0-alpha.4 → 0.1.0-alpha.7

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.
@@ -4,22 +4,22 @@ import * as Schema from "effect/Schema";
4
4
  import { EDACommand } from "effect-durable-agent/types/commands";
5
5
  import { CommandId, SequenceNumber, SessionId } from "effect-durable-agent/types/core";
6
6
  import { EDATraceMetadata } from "effect-durable-agent/types/tracing";
7
- import { OpenAiLanguageModel } from "@effect/ai-openai";
8
7
  import * as Layer from "effect/Layer";
9
- import * as Tracer from "effect/Tracer";
8
+ import { CommittedCommandTerminalEvent, EDARuntime, EDARuntimeConfig } from "effect-durable-agent/services/runtime";
9
+ import { CommittedDurableEvent } from "effect-durable-agent/services/session-store";
10
10
  import { CompactionExecutor, CompactionPolicy } from "effect-durable-agent/services/compaction";
11
11
  import { EDAPromptProjector } from "effect-durable-agent/services/prompt-projector";
12
12
  import { EDAReducer } from "effect-durable-agent/services/reducer-registry";
13
- import { CommittedCommandTerminalEvent, EDARuntime, EDARuntimeConfig } from "effect-durable-agent/services/runtime";
14
- import { CommittedDurableEvent, EDASessionStoreError } from "effect-durable-agent/services/session-store";
15
- import * as LanguageModel from "effect/unstable/ai/LanguageModel";
13
+ import { SessionEventObserver } from "effect-durable-agent/services/session-event-observer";
14
+ import { EDAWebSocketClientFrame, EDAWebSocketServerFrameEncoder, EDAWebSocketServerFrameInput } from "effect-durable-agent/websocket";
16
15
  import { DurableTranscriptMessage } from "effect-durable-agent/domain/message-transcript";
17
16
  import { EDASessionSnapshot } from "effect-durable-agent/services/session-query";
18
17
  import { EDASubmittable, SessionCommandAdmissionError } from "effect-durable-agent/services/session-state";
18
+ import * as LanguageModel from "effect/unstable/ai/LanguageModel";
19
+ import * as Tracer from "effect/Tracer";
19
20
  import { EDASink } from "effect-durable-agent/services/sink-registry";
20
21
  import { EDAModelToolkit, EDAToolRegistryShape } from "effect-durable-agent/services/tool-registry";
21
22
  import * as Fiber from "effect/Fiber";
22
- import { EDAWebSocketServerFrameEncoder } from "effect-durable-agent/host/websocket-wire";
23
23
 
24
24
  //#region src/durable-object-keepalive.d.ts
25
25
  /** Minimal Durable Object storage alarm surface needed by the EDA host keepalive. */
@@ -28,7 +28,11 @@ interface DurableObjectAlarmStorage {
28
28
  readonly setAlarm: (scheduledTimeMs: number) => void | Promise<void>;
29
29
  readonly deleteAlarm: () => void | Promise<void>;
30
30
  }
31
- /** Optional host hook for background alarm writes started from synchronous observers. */
31
+ /**
32
+ * Optional host hook for background alarm writes started from synchronous observers.
33
+ * Durable Objects already track their own async work; this hook does not keep an
34
+ * accepted WebSocket active or prevent WebSocket hibernation.
35
+ */
32
36
  interface DurableObjectBackgroundWaiter {
33
37
  readonly waitUntil: (promise: Promise<unknown>) => void;
34
38
  }
@@ -96,10 +100,10 @@ declare class DurableObjectKeepAlive {
96
100
  private syncAlarm;
97
101
  }
98
102
  //#endregion
99
- //#region src/durable-object-runtime.d.ts
100
- /** Durable Object storage capabilities needed by the EDA session host. */
103
+ //#region src/runtime/runtime-layer.d.ts
104
+ /** Storage capabilities used by one EDA session Durable Object. */
101
105
  type EDASessionDurableObjectStorage = DurableObjectSessionStorage & DurableObjectAlarmStorage;
102
- /** Options for composing one EDA runtime inside a raw Durable Object. */
106
+ /** Host adapters and application policy needed to build one session runtime. */
103
107
  interface EDADurableObjectRuntimeLayerOptions {
104
108
  readonly config: EDARuntimeConfig;
105
109
  readonly compactionExecutorLayer?: Layer.Layer<CompactionExecutor, never, LanguageModel.LanguageModel>;
@@ -107,7 +111,8 @@ interface EDADurableObjectRuntimeLayerOptions {
107
111
  readonly keepAlive?: DurableObjectKeepAlive;
108
112
  readonly modelLayer: Layer.Layer<LanguageModel.LanguageModel>;
109
113
  readonly promptProjectorLayer?: Layer.Layer<EDAPromptProjector>;
110
- readonly reducers?: ReadonlyArray<EDAReducer<any>>;
114
+ readonly reducers?: ReadonlyArray<EDAReducer>;
115
+ readonly sessionEventObserverLayer?: Layer.Layer<SessionEventObserver>;
111
116
  readonly sessionId: SessionId;
112
117
  readonly sinks?: ReadonlyArray<EDASink>;
113
118
  readonly storage: EDASessionDurableObjectStorage;
@@ -115,8 +120,36 @@ interface EDADurableObjectRuntimeLayerOptions {
115
120
  readonly toolRegistry?: EDAToolRegistryShape;
116
121
  readonly tracer?: Tracer.Tracer;
117
122
  }
118
- /** Options for one live raw Durable Object host instance. */
119
- interface EDASessionDurableObjectHostOptions {
123
+ /** Compose the platform-neutral runtime with Cloudflare persistence and lifecycle adapters. */
124
+ declare const makeEDADurableObjectRuntimeLayer: ({
125
+ config,
126
+ compactionExecutorLayer,
127
+ compactionPolicyLayer,
128
+ keepAlive,
129
+ modelLayer,
130
+ promptProjectorLayer,
131
+ reducers,
132
+ sessionEventObserverLayer,
133
+ sessionId,
134
+ sinks,
135
+ storage,
136
+ toolkit,
137
+ toolRegistry,
138
+ tracer
139
+ }: EDADurableObjectRuntimeLayerOptions) => Layer.Layer<EDARuntime, SessionCommandAdmissionError>;
140
+ //#endregion
141
+ //#region src/runtime/session-runtime.d.ts
142
+ type EDAToolkitFactory = (input: {
143
+ readonly sessionId: SessionId;
144
+ }) => EDAModelToolkit;
145
+ type EDAToolRegistryFactory = (input: {
146
+ readonly sessionId: SessionId;
147
+ }) => EDAToolRegistryShape;
148
+ type EDATracerFactory = (input: {
149
+ readonly sessionId: SessionId;
150
+ }) => Tracer.Tracer;
151
+ /** Configuration owned by the lazy per-isolate Effect runtime. */
152
+ interface EDASessionRuntimeOptions {
120
153
  readonly background?: DurableObjectBackgroundWaiter;
121
154
  readonly config: EDARuntimeConfig;
122
155
  readonly compactionExecutorLayer?: Layer.Layer<CompactionExecutor, never, LanguageModel.LanguageModel>;
@@ -124,142 +157,135 @@ interface EDASessionDurableObjectHostOptions {
124
157
  readonly keepAlive?: DurableObjectKeepAlive;
125
158
  readonly modelLayer: Layer.Layer<LanguageModel.LanguageModel>;
126
159
  readonly promptProjectorLayer?: Layer.Layer<EDAPromptProjector>;
127
- readonly reducers?: ReadonlyArray<EDAReducer<any>>;
160
+ readonly reducers?: ReadonlyArray<EDAReducer>;
161
+ readonly sessionEventObserverLayer: Layer.Layer<SessionEventObserver>;
128
162
  readonly sinks?: ReadonlyArray<EDASink>;
129
163
  readonly storage: EDASessionDurableObjectStorage;
130
164
  readonly toolkit?: EDAModelToolkit | EDAToolkitFactory;
131
165
  readonly toolRegistry?: EDAToolRegistryShape | EDAToolRegistryFactory;
132
166
  readonly tracer?: Tracer.Tracer | EDATracerFactory;
167
+ }
168
+ //#endregion
169
+ //#region src/websocket/projection.d.ts
170
+ /** Stable non-empty identity persisted with an app WebSocket projection. */
171
+ declare const EDAWebSocketProjectionId: Schema.brand<Schema.NonEmptyString, "EDAWebSocketProjectionId">;
172
+ type EDAWebSocketProjectionId = typeof EDAWebSocketProjectionId.Type;
173
+ /** Initial state and cursor selected when an app-projected WebSocket is accepted. */
174
+ interface EDAWebSocketProjectionInitial<State extends object> {
175
+ readonly afterSeq: SequenceNumber;
176
+ readonly state: State;
177
+ }
178
+ /** App projection decision for one EDA delivery frame. */
179
+ type EDAWebSocketProjectionResult<State extends object> = {
180
+ readonly _tag: "Send";
181
+ readonly frame: string;
182
+ readonly state: State;
183
+ } | {
184
+ /** Suppress an internal-only events frame and advance its ACK in the host. */readonly _tag: "SuppressAndAck";
185
+ readonly state: State;
186
+ };
187
+ /**
188
+ * App-owned wire projection hosted directly by the EDA Durable Object.
189
+ *
190
+ * The host persists `State` beside EDA delivery state, so an app can retain a
191
+ * stable public protocol without placing a resident WebSocket bridge in front
192
+ * of the hibernating object.
193
+ */
194
+ interface EDAWebSocketProjection<State extends object> {
195
+ /** Stable identifier persisted in WebSocket attachments. */
196
+ readonly id: EDAWebSocketProjectionId;
197
+ /** Decode one app-protocol client message into EDA's delivery ACK protocol. */
198
+ readonly decodeClientMessage: (message: string) => Effect.Effect<EDAWebSocketClientFrame, unknown>;
199
+ /** Restore app-owned connection state after isolate eviction. */
200
+ readonly decodeState: (encoded: unknown) => Effect.Effect<State, unknown>;
201
+ /** Encode app-owned connection state for Cloudflare's attachment boundary. */
202
+ readonly encodeState: (state: State) => unknown;
203
+ /** Project one EDA server frame while updating app-owned connection state. */
204
+ readonly encodeServerFrame: (frame: EDAWebSocketServerFrameInput, state: State) => EDAWebSocketProjectionResult<State>;
205
+ /** Seed the projection and select its default replay cursor from a durable snapshot. */
206
+ readonly initialize: (input: {
207
+ readonly requestedAfterSeq?: SequenceNumber;
208
+ readonly snapshot: EDASessionSnapshot;
209
+ }) => EDAWebSocketProjectionInitial<State>;
210
+ }
211
+ //#endregion
212
+ //#region src/session-controller.d.ts
213
+ /** Composition options for the session use cases and Cloudflare adapters. */
214
+ interface EDASessionControllerOptions<ProjectionState extends object = never> extends Omit<EDASessionRuntimeOptions, "sessionEventObserverLayer"> {
215
+ readonly getWebSockets?: () => ReadonlyArray<WebSocket>;
216
+ readonly webSocketProjection?: EDAWebSocketProjection<ProjectionState>;
133
217
  readonly webSocketProtocol?: EDAWebSocketServerFrameEncoder;
134
218
  }
135
- /** Per-session factory for provider-visible model toolkit definitions. */
136
- type EDAToolkitFactory = (input: {
137
- readonly sessionId: SessionId;
138
- }) => EDAModelToolkit;
139
- /** Per-session factory for custom tool registry implementations. */
140
- type EDAToolRegistryFactory = (input: {
141
- readonly sessionId: SessionId;
142
- }) => EDAToolRegistryShape;
143
- type EDATracerFactory = (input: {
144
- readonly sessionId: SessionId;
145
- }) => Tracer.Tracer;
146
- /** Typed host input for admitting one command through RPC or route code. */
147
219
  interface EDASessionSubmitInput {
148
220
  readonly command: EDACommand;
149
221
  readonly sessionId: SessionId;
150
- readonly trace: EDATraceMetadata;
222
+ readonly trace?: EDATraceMetadata;
151
223
  }
152
- /** Typed host input for admitting commands and app events as one durable batch. */
153
224
  interface EDASessionSubmitBatchInput {
154
225
  readonly items: ReadonlyArray<EDASubmittable>;
155
226
  readonly sessionId: SessionId;
156
- readonly trace: EDATraceMetadata;
227
+ readonly trace?: EDATraceMetadata;
157
228
  }
158
- /** Typed host input for waiting on a command terminal boundary. */
159
229
  interface EDASessionBlockOnCommandInput {
160
230
  readonly afterSeq?: SequenceNumber;
161
231
  readonly commandId: CommandId;
162
232
  readonly sessionId: SessionId;
163
- readonly trace: EDATraceMetadata;
233
+ readonly trace?: EDATraceMetadata;
164
234
  }
165
- /** Typed host input for operations scoped only by session identity. */
166
235
  interface EDASessionScopedInput {
167
236
  readonly sessionId: SessionId;
168
- readonly trace: EDATraceMetadata;
237
+ readonly trace?: EDATraceMetadata;
169
238
  }
170
- /** Typed host input for opening a live event stream from a durable cursor. */
171
239
  interface EDASessionEventsInput {
172
240
  readonly afterSeq?: SequenceNumber;
173
241
  readonly sessionId: SessionId;
242
+ readonly trace?: EDATraceMetadata;
243
+ }
244
+ /** Prepared acceptance state created before a Cloudflare socket is registered. */
245
+ interface EDAPreparedEventWebSocket<ProjectionState extends object = never> {
246
+ readonly afterSeq: SequenceNumber;
247
+ readonly sessionId: SessionId;
174
248
  readonly trace: EDATraceMetadata;
249
+ readonly projectionState?: ProjectionState;
175
250
  }
176
251
  /**
177
- * Compose the full EDA service graph for one raw Durable Object session.
252
+ * Public application-facing use cases for one EDA session.
178
253
  *
179
- * The layer is intentionally host-owned: tests can pass a fake model layer,
180
- * while the Worker host can pass a provider-backed layer from Env.
254
+ * Runtime lifecycle belongs to EDASessionRuntime; WebSocket transport belongs
255
+ * to EDAWebSocketConnectionManager. This class only coordinates them.
181
256
  */
182
- declare const makeEDADurableObjectRuntimeLayer: ({
183
- config,
184
- compactionExecutorLayer,
185
- compactionPolicyLayer,
186
- keepAlive,
187
- modelLayer,
188
- promptProjectorLayer,
189
- reducers,
190
- sessionId,
191
- sinks,
192
- storage,
193
- toolkit,
194
- toolRegistry,
195
- tracer
196
- }: EDADurableObjectRuntimeLayerOptions) => Layer.Layer<EDARuntime, SessionCommandAdmissionError>;
197
- /** Provider request defaults accepted by EDA's OpenAI Responses model adapter. */
198
- type EDAOpenAiModelConfig = Omit<typeof OpenAiLanguageModel.Config.Service, "model">;
199
- /** OpenAI-backed Effect AI model layer for the default Worker host. */
200
- declare const makeEDADurableObjectOpenAiModelLayer: (options: {
201
- readonly aiGateway?: AiGateway;
202
- readonly apiKey?: string;
203
- readonly apiUrl?: string;
204
- readonly config?: EDAOpenAiModelConfig;
205
- readonly modelId: string;
206
- }) => Layer.Layer<LanguageModel.LanguageModel>;
207
- /** Raw Durable Object host controller for one EDA session object. */
208
- declare class EDASessionDurableObjectHost {
209
- private readonly options;
210
- private readonly keepAlive;
211
- private readonly eventSockets;
212
- private runtimeState;
213
- private runtimePromise;
214
- constructor(options: EDASessionDurableObjectHostOptions);
215
- /** Run idempotent host and event-store migrations. Safe from `blockConcurrencyWhile`. */
216
- static readonly migrate: (storage: EDASessionDurableObjectStorage) => Effect.Effect<void, EDASessionStoreError>;
217
- /** Admit one command durably. Active runtime work holds EDA keep-alive leases internally. */
257
+ declare class EDASessionController<ProjectionState extends object = never> {
258
+ private readonly runtime;
259
+ private readonly webSockets;
260
+ constructor(options: EDASessionControllerOptions<ProjectionState>);
261
+ static readonly migrate: (storage: EDASessionDurableObjectStorage) => Effect.Effect<void, import("effect-durable-agent/services/session-store").EDASessionStoreError>;
218
262
  submit(input: EDASessionSubmitInput): Promise<CommittedDurableEvent>;
219
- /** Submit an ordered durable batch of commands and app events. */
220
263
  submitBatch(input: EDASessionSubmitBatchInput): Promise<ReadonlyArray<CommittedDurableEvent>>;
221
- /** Admit one command and wait for its terminal command boundary. */
222
264
  submitAndBlock(input: EDASessionSubmitInput): Promise<CommittedCommandTerminalEvent>;
223
- /** Wait for an existing command to reach its terminal command boundary. */
224
265
  blockOnCommand(input: EDASessionBlockOnCommandInput): Promise<CommittedCommandTerminalEvent>;
225
- /** Read the authoritative live session snapshot. */
226
266
  snapshot(input: EDASessionScopedInput): Promise<EDASessionSnapshot>;
227
- /** Read durable transcript messages in committed order. */
228
267
  messages(input: EDASessionScopedInput): Promise<ReadonlyArray<DurableTranscriptMessage>>;
229
- /** Accept one WebSocket as the live event stream for this session. */
230
268
  acceptEventWebSocket(input: EDASessionEventsInput & {
269
+ readonly projectionId?: string;
270
+ readonly webSocket: WebSocket;
271
+ }): Promise<void>;
272
+ private acceptEventWebSocketUnhosted;
273
+ prepareEventWebSocket(input: EDASessionEventsInput & {
274
+ readonly projectionId?: string;
275
+ }): Promise<EDAPreparedEventWebSocket<ProjectionState>>;
276
+ acceptPreparedEventWebSocket(input: EDAPreparedEventWebSocket<ProjectionState> & {
231
277
  readonly webSocket: WebSocket;
232
278
  }): Promise<void>;
233
- /** Restore hibernated event WebSockets whose in-memory subscriber fibers disappeared. */
234
- restoreEventWebSockets(webSockets: ReadonlyArray<WebSocket>): Promise<void>;
235
- /** Route one inbound WebSocket message into the subscriber ACK queue. */
236
279
  webSocketMessage(webSocket: WebSocket, message: string | ArrayBuffer): Promise<void>;
237
- /** Interrupt subscriber work after the client closes the WebSocket. */
238
- webSocketClose(webSocket: WebSocket): Promise<void>;
239
- /** Interrupt subscriber work after a host WebSocket error. */
240
- webSocketError(webSocket: WebSocket): Promise<void>;
241
- /** Dispose any live runtime before the host deletes its Durable Object storage. */
280
+ webSocketClose(webSocket: WebSocket): void;
281
+ webSocketError(webSocket: WebSocket): void;
242
282
  destroy(_input: EDASessionScopedInput): Promise<void>;
243
- /** Durable Object alarm hook: wake/recover the runtime and re-arm while EDA has active work. */
244
283
  alarm(input?: EDASessionScopedInput): Promise<void>;
245
- /** Dispose the Effect runtime if the host wrapper is torn down by tests. */
246
284
  dispose(): Promise<void>;
247
- private withRuntime;
248
- private ensureEventWebSocket;
249
- private startEventWebSocket;
250
- private getRuntime;
251
- private buildRuntime;
285
+ private query;
286
+ private prepareSession;
287
+ private run;
252
288
  }
253
- /** Decode a raw RPC command payload at the Durable Object boundary. */
254
- declare const encodeEdaRpcCommand: (input: EDACommand) => unknown;
255
- /** Encode a command/app-event batch into structured-clone-safe RPC values. */
256
- declare const encodeEdaRpcSubmittables: (input: ReadonlyArray<EDASubmittable>) => ReadonlyArray<unknown>;
257
- /** Decode a raw RPC command payload at the Durable Object boundary. */
258
- declare const decodeEdaRpcCommand: (input: unknown) => Effect.Effect<EDACommand, Schema.SchemaError>;
259
- /** Decode a raw RPC batch item at the Durable Object boundary. */
260
- declare const decodeEdaRpcSubmittable: (input: unknown) => Effect.Effect<EDASubmittable, Schema.SchemaError>;
261
- /** Decode raw RPC batch items at the Durable Object boundary. */
262
- declare const decodeEdaRpcSubmittables: (input: ReadonlyArray<unknown>) => Effect.Effect<ReadonlyArray<EDASubmittable>, Schema.SchemaError>;
263
289
  //#endregion
264
- export { encodeEdaRpcCommand as _, EDASessionDurableObjectHostOptions as a, makeEDADurableObjectRuntimeLayer as b, EDASessionScopedInput as c, EDAToolRegistryFactory as d, EDAToolkitFactory as f, decodeEdaRpcSubmittables as g, decodeEdaRpcSubmittable as h, EDASessionDurableObjectHost as i, EDASessionSubmitBatchInput as l, decodeEdaRpcCommand as m, EDAOpenAiModelConfig as n, EDASessionDurableObjectStorage as o, EDATracerFactory as p, EDASessionBlockOnCommandInput as r, EDASessionEventsInput as s, EDADurableObjectRuntimeLayerOptions as t, EDASessionSubmitInput as u, encodeEdaRpcSubmittables as v, makeEDADurableObjectOpenAiModelLayer as y };
265
- //# sourceMappingURL=durable-object-runtime-Dehm7PsO.d.ts.map
290
+ export { EDASessionEventsInput as a, EDASessionSubmitInput as c, EDAWebSocketProjectionInitial as d, EDAWebSocketProjectionResult as f, makeEDADurableObjectRuntimeLayer as h, EDASessionControllerOptions as i, EDAWebSocketProjection as l, EDASessionDurableObjectStorage as m, EDASessionBlockOnCommandInput as n, EDASessionScopedInput as o, EDADurableObjectRuntimeLayerOptions as p, EDASessionController as r, EDASessionSubmitBatchInput as s, EDAPreparedEventWebSocket as t, EDAWebSocketProjectionId as u };
291
+ //# sourceMappingURL=session-controller-BCsOxE22.d.ts.map