@effect-agent/platform-node 0.1.0-beta.56 → 0.1.0-beta.58

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.
@@ -1,8 +1,9 @@
1
1
  import { t as NodeWakeSchedulerConfig } from "./NodeWakeScheduler-4ZeXYwPu.mjs";
2
- import { a as NodeDurableAgentRuntimeOptions, c as NodePlatformConfigError, n as NodeDurableAgentRuntimeConfig, o as NodeDurableAgentRuntimeServices } from "./NodeDurableAgentRuntime-CPmWN-L_.mjs";
2
+ import { a as NodeDurableAgentRuntimeOptions, c as NodePlatformConfigError, n as NodeDurableAgentRuntimeConfig, o as NodeDurableAgentRuntimeServices } from "./NodeDurableAgentRuntime-CFElFzNF.mjs";
3
3
  import { SubmissionId, ThreadId } from "@effect-agent/core/Identifiers";
4
4
  import { AgentRegistration, DurableBindingFailure, ResolvedBinding } from "@effect-agent/thread/AgentRegistration";
5
5
  import { DurableAbortFailure, DurableAgentRuntime, DurableAwaitFailure, DurableExplainFailure, DurableObligationFailure, DurableObserveOptions, DurableRetryFailure, DurableSubmitAgent, DurableSubmitFailure, DurableSubmitOptions, DurableVerifyFailure, DurableWorkerFailure, Receipt, RecoveryReport } from "@effect-agent/thread/DurableAgentRuntime";
6
+ import { MessageDeliveryError, MessageDeliveryStore } from "@effect-agent/thread/MessageDelivery";
6
7
  import { CanonicalRecordEnvelope } from "@effect-agent/thread/Records";
7
8
  import { AbortCommand, AbortIntent, Settlement } from "@effect-agent/thread/SubmissionLedger";
8
9
  import { ThreadNotMaterialized, ThreadStoreError } from "@effect-agent/thread/ThreadStore";
@@ -52,7 +53,8 @@ declare const NodeDurableHost_base: Context.ServiceClass<NodeDurableHost, "@effe
52
53
  /**
53
54
  * Run `workerConcurrency` copies of the given worker effect (typically
54
55
  * `DurableAgentRuntime.runWorker(agent)`) until the caller's Scope interrupts them. The
55
- * bound is the validated finite configuration value; the host never forks daemon fibers.
56
+ * same Scope drives pending message admission and settlement observation independently
57
+ * of Submission liveness. The host never forks daemon fibers.
56
58
  */
57
59
  readonly runWorkers: <A, E, R>(worker: Effect.Effect<A, E, R>) => Effect.Effect<void, E, R>;
58
60
  /**
@@ -85,11 +87,11 @@ declare class NodeDurableHost extends NodeDurableHost_base {
85
87
  * Startup recovery and shutdown gates are unchanged. Workers start only when the caller
86
88
  * runs runResolvedWorkers; this constructor never starts a background worker.
87
89
  */
88
- static layerRegistered<const Entries extends ReadonlyArray<AgentRegistration>, ContextError = never, ContextRequirements = never, AuthorizationError = never, AuthorizationRequirements = never, ReconcilerError = never, ReconcilerRequirements = never>(registrations: Entries, options: NodeDurableAgentRuntimeOptions<ContextError, ContextRequirements, AuthorizationError, AuthorizationRequirements, ReconcilerError, ReconcilerRequirements>): Layer.Layer<NodeDurableHost | NodeDurableAgentRuntimeServices, AuthorizationError | ContextError | ReconcilerError | NodePlatformConfigError | DurableWorkerFailure | import("@effect-agent/storage-sqlite/SqliteThreadStore").SqliteStorageInitializationError, Exclude<AuthorizationRequirements, import("effect/Crypto").Crypto> | Exclude<ContextRequirements, import("effect/Crypto").Crypto> | Exclude<Exclude<Exclude<ReconcilerRequirements, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization> | Exclude<Exclude<Exclude<Exclude<Exclude<Exclude<[Entries[number]] extends [never] ? never : Entries[number] extends (infer T_2) ? T_2 extends Entries[number] ? T_2 extends {
90
+ static layerRegistered<const Entries extends ReadonlyArray<AgentRegistration>, ContextError = never, ContextRequirements = never, AuthorizationError = never, AuthorizationRequirements = never, ReconcilerError = never, ReconcilerRequirements = never>(registrations: Entries, options: NodeDurableAgentRuntimeOptions<ContextError, ContextRequirements, AuthorizationError, AuthorizationRequirements, ReconcilerError, ReconcilerRequirements>): Layer.Layer<NodeDurableHost | NodeDurableAgentRuntimeServices, AuthorizationError | ContextError | ReconcilerError | MessageDeliveryError | NodePlatformConfigError | DurableWorkerFailure | import("@effect-agent/storage-sqlite/SqliteThreadStore").SqliteStorageInitializationError, Exclude<AuthorizationRequirements, import("effect/Crypto").Crypto> | Exclude<ContextRequirements, import("effect/Crypto").Crypto> | Exclude<Exclude<Exclude<ReconcilerRequirements, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization> | Exclude<Exclude<Exclude<Exclude<Exclude<Exclude<[Entries[number]] extends [never] ? never : (Entries[number] extends (infer T_3) ? T_3 extends Entries[number] ? T_3 extends {
89
91
  readonly attemptLayer: (context: import("@effect-agent/thread/AgentRegistration").AgentAttemptContext) => Layer.Layer<infer Provides, never, infer Requires>;
90
- } ? Requires | Exclude<T_2 extends (infer T_3) ? T_3 extends T_2 ? T_3 extends {
92
+ } ? Requires | Exclude<T_3 extends (infer T_4) ? T_4 extends T_3 ? T_4 extends {
91
93
  readonly agent: infer A extends import("@effect-agent/thread/AgentRegistration").ExecutableAgentBinding;
92
- } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<A> : T_3 extends {
94
+ } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<A> : T_4 extends {
93
95
  readonly agent: infer D extends import("@effect-agent/core/Agent").Definition<Schema.Top, Schema.Top, unknown, import("effect/unstable/ai/Toolkit").Any, import("@effect-agent/core/Agent").RunDispositionDeclaration<never, Schema.Top> | undefined, unknown> & {
94
96
  readonly instructions: import("@effect-agent/core/Agent").InstructionSource<never, unknown, unknown>;
95
97
  readonly inputPrompt?: import("@effect-agent/core/Agent").InputPromptSource<never, unknown, unknown> | undefined;
@@ -98,9 +100,9 @@ declare class NodeDurableHost extends NodeDurableHost_base {
98
100
  } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<{
99
101
  readonly definition: D;
100
102
  readonly model: M;
101
- }> : never : never : never, Provides> : T_2 extends {
103
+ }> : never : never : never, Provides> : T_3 extends {
102
104
  readonly agent: infer A extends import("@effect-agent/thread/AgentRegistration").ExecutableAgentBinding;
103
- } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<A> : T_2 extends {
105
+ } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<A> : T_3 extends {
104
106
  readonly agent: infer D extends import("@effect-agent/core/Agent").Definition<Schema.Top, Schema.Top, unknown, import("effect/unstable/ai/Toolkit").Any, import("@effect-agent/core/Agent").RunDispositionDeclaration<never, Schema.Top> | undefined, unknown> & {
105
107
  readonly instructions: import("@effect-agent/core/Agent").InstructionSource<never, unknown, unknown>;
106
108
  readonly inputPrompt?: import("@effect-agent/core/Agent").InputPromptSource<never, unknown, unknown> | undefined;
@@ -109,16 +111,18 @@ declare class NodeDurableHost extends NodeDurableHost_base {
109
111
  } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<{
110
112
  readonly definition: D;
111
113
  readonly model: M;
112
- }> : never : never : never, import("effect/Scope").Scope>, import("@effect-agent/thread/DurableAgentRuntime").DurableRuntimeConfig | import("@effect-agent/thread/Schedule").ScheduleStore | import("@effect-agent/thread/SubmissionLedger").SubmissionLedger | import("@effect-agent/thread/ThreadStore").ThreadStore | import("@effect-agent/thread/WakeScheduler").WakeScheduler>, import("@effect-agent/thread/DurableFailpoint").DurableRuntimeFailpoint | NodeWakeSchedulerConfig | import("@effect-agent/thread/ToolReconciler").ToolReconciler>, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization>>;
114
+ }> : never : never : never) | (Entries[number] extends (infer T_5) ? T_5 extends Entries[number] ? T_5 extends {
115
+ readonly reporting: infer Reports extends ReadonlyArray<import("@effect-agent/engine/SubagentHost").WorkerReporting<unknown, unknown>>;
116
+ } ? [Reports[number]] extends [never] ? never : Reports[number] extends import("@effect-agent/engine/SubagentHost").WorkerReporting<unknown, infer R> ? Exclude<R, import("effect/Scope").Scope> : never : never : never : never), import("effect/Scope").Scope>, import("@effect-agent/thread/DurableAgentRuntime").DurableRuntimeConfig | MessageDeliveryStore | import("@effect-agent/thread/Schedule").ScheduleStore | import("@effect-agent/thread/SubmissionLedger").SubmissionLedger | import("@effect-agent/thread/ThreadStore").ThreadStore | import("@effect-agent/thread/WakeScheduler").WakeScheduler>, import("@effect-agent/thread/DurableFailpoint").DurableRuntimeFailpoint | NodeWakeSchedulerConfig | import("@effect-agent/thread/ToolReconciler").ToolReconciler>, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization>>;
113
117
  /**
114
118
  * Host gates over an assembled `NodeDurableAgentRuntime` stack. The runtime Layer owns
115
119
  * executable registrations; omission registers no Agents, so resolved work fails closed.
116
120
  */
117
- static readonly layer: Layer.Layer<NodeDurableHost, DurableWorkerFailure, DurableAgentRuntime | NodeDurableAgentRuntimeConfig>;
121
+ static readonly layer: Layer.Layer<NodeDurableHost, DurableWorkerFailure | MessageDeliveryError, DurableAgentRuntime | NodeDurableAgentRuntimeConfig | MessageDeliveryStore>;
118
122
  /** The complete DN host: `NodeDurableAgentRuntime.layer(options)` plus the host lifecycle gates. */
119
123
  static layerStack<ContextError = never, ContextRequirements = never, AuthorizationError = never, AuthorizationRequirements = never, ReconcilerError = never, ReconcilerRequirements = never>(options: NodeDurableAgentRuntimeOptions<ContextError, ContextRequirements, AuthorizationError, AuthorizationRequirements, ReconcilerError, ReconcilerRequirements> & {
120
124
  readonly bindings?: ReadonlyArray<ResolvedBinding>;
121
- }): Layer.Layer<NodeDurableHost | NodeDurableAgentRuntimeServices, AuthorizationError | ContextError | ReconcilerError | NodePlatformConfigError | DurableWorkerFailure | import("@effect-agent/storage-sqlite/SqliteThreadStore").SqliteStorageInitializationError, Exclude<AuthorizationRequirements, import("effect/Crypto").Crypto> | Exclude<ContextRequirements, import("effect/Crypto").Crypto> | Exclude<Exclude<Exclude<ReconcilerRequirements, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization>>;
125
+ }): Layer.Layer<NodeDurableHost | NodeDurableAgentRuntimeServices, AuthorizationError | ContextError | ReconcilerError | MessageDeliveryError | NodePlatformConfigError | DurableWorkerFailure | import("@effect-agent/storage-sqlite/SqliteThreadStore").SqliteStorageInitializationError, Exclude<AuthorizationRequirements, import("effect/Crypto").Crypto> | Exclude<ContextRequirements, import("effect/Crypto").Crypto> | Exclude<Exclude<Exclude<ReconcilerRequirements, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization>>;
122
126
  }
123
127
  /**
124
128
  * Acquire a complete Node host and start one bounded, scoped worker pool after recovery.
@@ -126,11 +130,11 @@ declare class NodeDurableHost extends NodeDurableHost_base {
126
130
  * shares the same pool. A worker failure closes admission; observe it with `run` at the process
127
131
  * boundary so the application exits and releases the host instead of remaining idle.
128
132
  */
129
- declare const layer: <const Entries extends ReadonlyArray<AgentRegistration>, ContextError = never, ContextRequirements = never, AuthorizationError = never, AuthorizationRequirements = never, ReconcilerError = never, ReconcilerRequirements = never>(registrations: Entries, options: NodeDurableAgentRuntimeOptions<ContextError, ContextRequirements, AuthorizationError, AuthorizationRequirements, ReconcilerError, ReconcilerRequirements>) => Layer.Layer<NodeDurableHost | NodeDurableAgentRuntimeServices, AuthorizationError | ContextError | ReconcilerError | NodePlatformConfigError | DurableWorkerFailure | import("@effect-agent/storage-sqlite/SqliteThreadStore").SqliteStorageInitializationError, Exclude<AuthorizationRequirements, import("effect/Crypto").Crypto> | Exclude<ContextRequirements, import("effect/Crypto").Crypto> | Exclude<Exclude<Exclude<ReconcilerRequirements, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization> | Exclude<Exclude<Exclude<Exclude<Exclude<Exclude<[Entries[number]] extends [never] ? never : Entries[number] extends (infer T_2) ? T_2 extends Entries[number] ? T_2 extends {
133
+ declare const layer: <const Entries extends ReadonlyArray<AgentRegistration>, ContextError = never, ContextRequirements = never, AuthorizationError = never, AuthorizationRequirements = never, ReconcilerError = never, ReconcilerRequirements = never>(registrations: Entries, options: NodeDurableAgentRuntimeOptions<ContextError, ContextRequirements, AuthorizationError, AuthorizationRequirements, ReconcilerError, ReconcilerRequirements>) => Layer.Layer<NodeDurableHost | NodeDurableAgentRuntimeServices, AuthorizationError | ContextError | ReconcilerError | MessageDeliveryError | NodePlatformConfigError | DurableWorkerFailure | import("@effect-agent/storage-sqlite/SqliteThreadStore").SqliteStorageInitializationError, Exclude<AuthorizationRequirements, import("effect/Crypto").Crypto> | Exclude<ContextRequirements, import("effect/Crypto").Crypto> | Exclude<Exclude<Exclude<ReconcilerRequirements, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization> | Exclude<Exclude<Exclude<Exclude<Exclude<Exclude<[Entries[number]] extends [never] ? never : (Entries[number] extends (infer T_3) ? T_3 extends Entries[number] ? T_3 extends {
130
134
  readonly attemptLayer: (context: import("@effect-agent/thread/AgentRegistration").AgentAttemptContext) => Layer.Layer<infer Provides, never, infer Requires>;
131
- } ? Requires | Exclude<T_2 extends (infer T_3) ? T_3 extends T_2 ? T_3 extends {
135
+ } ? Requires | Exclude<T_3 extends (infer T_4) ? T_4 extends T_3 ? T_4 extends {
132
136
  readonly agent: infer A extends import("@effect-agent/thread/AgentRegistration").ExecutableAgentBinding;
133
- } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<A> : T_3 extends {
137
+ } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<A> : T_4 extends {
134
138
  readonly agent: infer D extends import("@effect-agent/core/Agent").Definition<Schema.Top, Schema.Top, unknown, import("effect/unstable/ai/Toolkit").Any, import("@effect-agent/core/Agent").RunDispositionDeclaration<never, Schema.Top> | undefined, unknown> & {
135
139
  readonly instructions: import("@effect-agent/core/Agent").InstructionSource<never, unknown, unknown>;
136
140
  readonly inputPrompt?: import("@effect-agent/core/Agent").InputPromptSource<never, unknown, unknown> | undefined;
@@ -139,9 +143,9 @@ declare const layer: <const Entries extends ReadonlyArray<AgentRegistration>, Co
139
143
  } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<{
140
144
  readonly definition: D;
141
145
  readonly model: M;
142
- }> : never : never : never, Provides> : T_2 extends {
146
+ }> : never : never : never, Provides> : T_3 extends {
143
147
  readonly agent: infer A extends import("@effect-agent/thread/AgentRegistration").ExecutableAgentBinding;
144
- } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<A> : T_2 extends {
148
+ } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<A> : T_3 extends {
145
149
  readonly agent: infer D extends import("@effect-agent/core/Agent").Definition<Schema.Top, Schema.Top, unknown, import("effect/unstable/ai/Toolkit").Any, import("@effect-agent/core/Agent").RunDispositionDeclaration<never, Schema.Top> | undefined, unknown> & {
146
150
  readonly instructions: import("@effect-agent/core/Agent").InstructionSource<never, unknown, unknown>;
147
151
  readonly inputPrompt?: import("@effect-agent/core/Agent").InputPromptSource<never, unknown, unknown> | undefined;
@@ -150,7 +154,9 @@ declare const layer: <const Entries extends ReadonlyArray<AgentRegistration>, Co
150
154
  } ? import("@effect-agent/thread/DurableAgentRuntime").DurableWorkerRequirements<{
151
155
  readonly definition: D;
152
156
  readonly model: M;
153
- }> : never : never : never, import("effect/Scope").Scope>, import("@effect-agent/thread/DurableAgentRuntime").DurableRuntimeConfig | import("@effect-agent/thread/Schedule").ScheduleStore | import("@effect-agent/thread/SubmissionLedger").SubmissionLedger | import("@effect-agent/thread/ThreadStore").ThreadStore | import("@effect-agent/thread/WakeScheduler").WakeScheduler>, import("@effect-agent/thread/DurableFailpoint").DurableRuntimeFailpoint | NodeWakeSchedulerConfig | import("@effect-agent/thread/ToolReconciler").ToolReconciler>, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization>>;
157
+ }> : never : never : never) | (Entries[number] extends (infer T_5) ? T_5 extends Entries[number] ? T_5 extends {
158
+ readonly reporting: infer Reports extends ReadonlyArray<import("@effect-agent/engine/SubagentHost").WorkerReporting<unknown, unknown>>;
159
+ } ? [Reports[number]] extends [never] ? never : Reports[number] extends import("@effect-agent/engine/SubagentHost").WorkerReporting<unknown, infer R> ? Exclude<R, import("effect/Scope").Scope> : never : never : never : never), import("effect/Scope").Scope>, import("@effect-agent/thread/DurableAgentRuntime").DurableRuntimeConfig | MessageDeliveryStore | import("@effect-agent/thread/Schedule").ScheduleStore | import("@effect-agent/thread/SubmissionLedger").SubmissionLedger | import("@effect-agent/thread/ThreadStore").ThreadStore | import("@effect-agent/thread/WakeScheduler").WakeScheduler>, import("@effect-agent/thread/DurableFailpoint").DurableRuntimeFailpoint | NodeWakeSchedulerConfig | import("@effect-agent/thread/ToolReconciler").ToolReconciler>, import("effect/Crypto").Crypto | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | import("@effect-agent/storage-sqlite/SqliteStorageConfig").SqliteStorageConfig | import("@effect-agent/storage-sqlite/SqliteStorageFailpoint").SqliteStorageFailpoint>, NodeDurableAgentRuntimeConfig>, import("@effect-agent/engine/RunOptions").RunContextPreparation | import("@effect-agent/engine/RunOptions").RunToolAuthorization>>;
154
160
  /**
155
161
  * Supervise the host's existing workers without starting another pool. Use with
156
162
  * `Effect.provide(HostLive)` and `NodeRuntime.runMain`; race it with a server Effect when
@@ -1,111 +1,2 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { NodeDurableAgentRuntime, NodeDurableAgentRuntimeConfig } from "./NodeDurableAgentRuntime.mjs";
3
- import "@effect-agent/core/Identifiers";
4
- import "@effect-agent/thread/AgentRegistration";
5
- import { DurableAgentRuntime } from "@effect-agent/thread/DurableAgentRuntime";
6
- import "@effect-agent/thread/Records";
7
- import "@effect-agent/thread/SubmissionLedger";
8
- import "@effect-agent/thread/ThreadStore";
9
- import { Context, Effect, Fiber, Layer, Ref, Schema } from "effect";
10
- import "@effect-agent/thread/Admin";
11
- import "@effect-agent/thread/OperationAuthorizer";
12
- //#region src/NodeDurableHost.ts
13
- var NodeDurableHost_exports = /* @__PURE__ */ __exportAll({
14
- AdmissionClosed: () => AdmissionClosed,
15
- NodeDurableHost: () => NodeDurableHost,
16
- layer: () => layer,
17
- run: () => run
18
- });
19
- /**
20
- * Admission is not open on this host: it is shutting down (deployment §6 step 1, DEPLOY-005).
21
- * Accepted work is unaffected — only NEW admissions are refused.
22
- */
23
- var AdmissionClosed = class extends Schema.TaggedError()("AdmissionClosed", { message: Schema.String }) {};
24
- const makeHost = Effect.fn("NodeDurableHost.make")(function* (startWorkers) {
25
- const runtime = yield* DurableAgentRuntime;
26
- const config = yield* NodeDurableAgentRuntimeConfig;
27
- const startupRecovery = yield* runtime.runRecovery;
28
- const admission = yield* Ref.make(true);
29
- const requireAdmission = Ref.get(admission).pipe(Effect.flatMap((open) => open ? Effect.void : Effect.fail(AdmissionClosed.make({ message: "The host is shutting down; admission is closed." }))));
30
- const submit = (agent, input, options) => requireAdmission.pipe(Effect.andThen(runtime.submit(agent, input, options)));
31
- const runWorkers = (worker) => Effect.forEach(Array.from({ length: config.workerConcurrency }, (_, index) => index), () => worker, {
32
- concurrency: "unbounded",
33
- discard: true
34
- });
35
- const runResolvedWorkers = runWorkers(runtime.runResolvedWorker);
36
- const run = startWorkers ? Fiber.join(yield* runResolvedWorkers.pipe(Effect.onExit(() => Ref.set(admission, false)), Effect.forkScoped)) : runResolvedWorkers;
37
- yield* Effect.addFinalizer(() => Ref.set(admission, false));
38
- return NodeDurableHost.of({
39
- startupRecovery,
40
- admissionOpen: Ref.get(admission),
41
- submit,
42
- awaitSettlement: runtime.awaitSettlement,
43
- submissionStatus: runtime.submissionStatus,
44
- observe: runtime.observe,
45
- abort: runtime.abort,
46
- explain: runtime.explain,
47
- explainThread: runtime.explainThread,
48
- verify: runtime.verify,
49
- retry: runtime.retry,
50
- wake: runtime.wake,
51
- scanObligations: runtime.scanObligations,
52
- runWorkers,
53
- run,
54
- runResolvedWorkers: run
55
- });
56
- });
57
- /**
58
- * Operational host service. Prefer the module's `layer` and `run` for managed workers.
59
- * The static constructors on this class retain explicit, manual worker ownership.
60
- *
61
- * Startup gates run during Layer construction, so the service existing implies readiness:
62
- * configuration was schema-decoded, the SQLite file passed the exact-version compatibility check,
63
- * and every nonterminal Submission went through one full recovery pass BEFORE admission opened.
64
- * `startupRecovery` is the auditable evidence of that reconciliation pass.
65
- *
66
- * Shutdown runs in reverse Layer order when the owning Scope closes: `submit` starts refusing
67
- * with `AdmissionClosed` first, then the runtime Layer's ownership drain releases every claim
68
- * still held so another host can take over the lanes immediately, then the SQLite resources
69
- * close. Forced termination at any point stays safe — the durability protocol, not graceful
70
- * shutdown, provides correctness (DEPLOY-006).
71
- */
72
- var NodeDurableHost = class NodeDurableHost extends Context.Service()("@effect-agent/platform-node/NodeDurableHost") {
73
- /**
74
- * Compile typed registrations and acquire the complete host in one Layer Scope.
75
- * Node supplies Crypto; model, tool, instruction, and schema services remain required.
76
- * Startup recovery and shutdown gates are unchanged. Workers start only when the caller
77
- * runs runResolvedWorkers; this constructor never starts a background worker.
78
- */
79
- static layerRegistered(registrations, options) {
80
- return NodeDurableHost.layer.pipe(Layer.provideMerge(NodeDurableAgentRuntime.layerRegistered(registrations, options)));
81
- }
82
- /**
83
- * Host gates over an assembled `NodeDurableAgentRuntime` stack. The runtime Layer owns
84
- * executable registrations; omission registers no Agents, so resolved work fails closed.
85
- */
86
- static layer = Layer.effect(NodeDurableHost)(makeHost(false));
87
- /** The complete DN host: `NodeDurableAgentRuntime.layer(options)` plus the host lifecycle gates. */
88
- static layerStack(options) {
89
- const { bindings = [], ...runtimeOptions } = options;
90
- return NodeDurableHost.layer.pipe(Layer.provideMerge(NodeDurableAgentRuntime.layerWithBindings(bindings, runtimeOptions)));
91
- }
92
- };
93
- /**
94
- * Acquire a complete Node host and start one bounded, scoped worker pool after recovery.
95
- * Provide model, tool, instruction, and schema dependencies to this Layer. Reusing the Layer
96
- * shares the same pool. A worker failure closes admission; observe it with `run` at the process
97
- * boundary so the application exits and releases the host instead of remaining idle.
98
- */
99
- const layer = (registrations, options) => Layer.effect(NodeDurableHost)(makeHost(true)).pipe(Layer.provideMerge(NodeDurableAgentRuntime.layerRegistered(registrations, options)));
100
- /**
101
- * Supervise the host's existing workers without starting another pool. Use with
102
- * `Effect.provide(HostLive)` and `NodeRuntime.runMain`; race it with a server Effect when
103
- * the same process also serves requests. Unlike `Layer.launch`, this observes worker failures.
104
- */
105
- const run = Effect.gen(function* () {
106
- return yield* (yield* NodeDurableHost).run;
107
- });
108
- //#endregion
109
- export { AdmissionClosed, NodeDurableHost, layer, run, NodeDurableHost_exports as t };
110
-
111
- //# sourceMappingURL=NodeDurableHost.mjs.map
1
+ import { a as run, i as layer, n as NodeDurableHost, t as AdmissionClosed } from "./NodeDurableHost-BMSajuQn.mjs";
2
+ export { AdmissionClosed, NodeDurableHost, layer, run };
@@ -1,8 +1,8 @@
1
1
  import { NodeDurableHost } from "./NodeDurableHost.mjs";
2
2
  import { ScheduledInputAdmission } from "@effect-agent/thread/Schedule";
3
3
  import { Layer } from "effect";
4
- import { EventSources } from "@effect-agent/thread/EventSource";
5
4
  import { PreparedInputAdmission } from "@effect-agent/thread/PreparedInputAdmission";
5
+ import { EventSources } from "@effect-agent/thread/EventSource";
6
6
  import { SubscriptionAuthorizer, SubscriptionError, SubscriptionLimits, SubscriptionStore } from "@effect-agent/thread/Subscription";
7
7
  import { SubscriptionInputBindings } from "@effect-agent/thread/SubscriptionInput";
8
8
  import { SubscriptionIntake, Subscriptions } from "@effect-agent/thread/Subscriptions";
@@ -1,13 +1,10 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { NodeDurableHost } from "./NodeDurableHost.mjs";
3
- import "@effect-agent/core/Identifiers";
4
- import "@effect-agent/thread/DurableAgentRuntime";
5
- import { PersistedJson } from "@effect-agent/thread/Records";
6
- import { ScheduleStorageError, ScheduledInputAdmission, ScheduledInputRefused, ScheduledInputRetryable } from "@effect-agent/thread/Schedule";
2
+ import { n as NodeDurableHost, o as NodeAdmission, s as makeNodePreparedInputAdmission } from "./NodeDurableHost-BMSajuQn.mjs";
3
+ import { ScheduledInputAdmission } from "@effect-agent/thread/Schedule";
7
4
  import { NodeCrypto } from "@effect/platform-node";
8
5
  import { Cause, Duration, Effect, Exit, Layer, Option } from "effect";
9
- import "@effect-agent/thread/EventSource";
10
6
  import { PreparedInputAdmission } from "@effect-agent/thread/PreparedInputAdmission";
7
+ import "@effect-agent/thread/EventSource";
11
8
  import { SubscriptionStore, defaultSubscriptionLimits } from "@effect-agent/thread/Subscription";
12
9
  import "@effect-agent/thread/SubscriptionInput";
13
10
  import { SubscriptionDriver, SubscriptionIntake, Subscriptions } from "@effect-agent/thread/Subscriptions";
@@ -17,42 +14,8 @@ var NodeSubscriptions_exports = /* @__PURE__ */ __exportAll({
17
14
  nodePreparedInputAdmissionLayer: () => nodePreparedInputAdmissionLayer,
18
15
  nodeScheduledInputAdmissionLayer: () => nodeScheduledInputAdmissionLayer
19
16
  });
20
- const passthroughSubmitAgent = (agentId) => ({ definition: {
21
- id: agentId,
22
- input: PersistedJson
23
- } });
24
- const ambiguous = () => ScheduledInputRetryable.make({ reason: "ambiguous" });
25
- const corrupt = (operation) => ScheduleStorageError.make({
26
- operation,
27
- reason: "corrupt"
28
- });
29
17
  /** Ordinary prepared admission through the Scope-owned Node host gate. */
30
- const nodePreparedInputAdmissionLayer = Layer.effect(PreparedInputAdmission, Effect.gen(function* () {
31
- const host = yield* NodeDurableHost;
32
- return PreparedInputAdmission.of({
33
- submissionStatus: (receipt) => host.submissionStatus(receipt).pipe(Effect.mapError(() => ScheduledInputRetryable.make({ reason: "storage" }))),
34
- submit: (envelope) => host.submit(passthroughSubmitAgent(envelope.agentId), envelope.input, {
35
- threadId: envelope.threadId,
36
- principal: envelope.deliveryPrincipal,
37
- idempotencyKey: envelope.admissionKey,
38
- ...envelope.admissionGroup === void 0 ? {} : { admissionGroup: envelope.admissionGroup },
39
- ...envelope.admissionFence === void 0 ? {} : { admissionFence: envelope.admissionFence },
40
- definitions: envelope.definitions
41
- }).pipe(Effect.catchTags({
42
- AdmissionClosed: () => Effect.fail(ScheduledInputRetryable.make({ reason: "host-closed" })),
43
- AgentInputError: () => Effect.fail(corrupt("prepared admission input")),
44
- AdmissionConflict: () => Effect.fail(corrupt("prepared admission conflict")),
45
- DigestError: () => Effect.fail(ambiguous()),
46
- AdmissionPolicyError: (error) => error.reason === "refused" ? ScheduledInputRefused.make({ code: error.code }) : ScheduledInputRetryable.make({ reason: error.reason === "occupied" ? "capacity" : "storage" }),
47
- LedgerError: () => ScheduledInputRetryable.make({ reason: "storage" }),
48
- ThreadStoreError: () => Effect.fail(ambiguous()),
49
- ThreadNotMaterialized: () => Effect.fail(ambiguous()),
50
- AppendConflict: () => Effect.fail(ambiguous()),
51
- FenceRejected: () => Effect.fail(ambiguous()),
52
- DurableRuntimeFailpointError: () => Effect.fail(ambiguous())
53
- }))
54
- });
55
- }));
18
+ const nodePreparedInputAdmissionLayer = Layer.effect(PreparedInputAdmission, makeNodePreparedInputAdmission).pipe(Layer.provide(Layer.effect(NodeAdmission, NodeDurableHost)));
56
19
  const preparedFromSchedule = (envelope) => ({
57
20
  schemaVersion: 1,
58
21
  threadId: envelope.threadId,
@@ -1 +1 @@
1
- {"version":3,"file":"NodeSubscriptions.mjs","names":[],"sources":["../src/NodeSubscriptions.ts"],"sourcesContent":["import { type AgentId } from \"@effect-agent/core/Identifiers\";\nimport { type DurableSubmitAgent } from \"@effect-agent/thread/DurableAgentRuntime\";\nimport { type EventSources } from \"@effect-agent/thread/EventSource\";\nimport { PreparedInputAdmission } from \"@effect-agent/thread/PreparedInputAdmission\";\nimport { PersistedJson } from \"@effect-agent/thread/Records\";\nimport {\n type ScheduledEnvelope,\n ScheduledInputAdmission,\n ScheduledInputRetryable,\n ScheduledInputRefused,\n ScheduleStorageError,\n} from \"@effect-agent/thread/Schedule\";\nimport {\n type PreparedInput,\n type SubscriptionAuthorizer,\n type SubscriptionError,\n type SubscriptionLimits,\n type SubscriptionStoreFailure,\n SubscriptionStore,\n defaultSubscriptionLimits,\n} from \"@effect-agent/thread/Subscription\";\nimport { type SubscriptionInputBindings } from \"@effect-agent/thread/SubscriptionInput\";\nimport {\n SubscriptionDriver,\n SubscriptionIntake,\n Subscriptions,\n} from \"@effect-agent/thread/Subscriptions\";\nimport { NodeCrypto } from \"@effect/platform-node\";\nimport { Cause, Duration, Effect, Exit, Layer, Option } from \"effect\";\n\nimport { NodeDurableHost } from \"./NodeDurableHost.ts\";\n\nconst passthroughSubmitAgent = (agentId: AgentId): DurableSubmitAgent<typeof PersistedJson> => ({\n definition: { id: agentId, input: PersistedJson },\n});\n\nconst ambiguous = (): ScheduledInputRetryable =>\n ScheduledInputRetryable.make({ reason: \"ambiguous\" });\n\nconst corrupt = (operation: string): ScheduleStorageError =>\n ScheduleStorageError.make({ operation, reason: \"corrupt\" });\n\n/** Ordinary prepared admission through the Scope-owned Node host gate. */\nexport const nodePreparedInputAdmissionLayer: Layer.Layer<\n PreparedInputAdmission,\n never,\n NodeDurableHost\n> = Layer.effect(\n PreparedInputAdmission,\n Effect.gen(function* () {\n const host = yield* NodeDurableHost;\n\n return PreparedInputAdmission.of({\n submissionStatus: (receipt) =>\n host\n .submissionStatus(receipt)\n .pipe(Effect.mapError(() => ScheduledInputRetryable.make({ reason: \"storage\" }))),\n submit: (envelope) =>\n host\n .submit(passthroughSubmitAgent(envelope.agentId), envelope.input, {\n threadId: envelope.threadId,\n principal: envelope.deliveryPrincipal,\n idempotencyKey: envelope.admissionKey,\n ...(envelope.admissionGroup === undefined\n ? {}\n : { admissionGroup: envelope.admissionGroup }),\n ...(envelope.admissionFence === undefined\n ? {}\n : { admissionFence: envelope.admissionFence }),\n definitions: envelope.definitions,\n })\n .pipe(\n Effect.catchTags({\n AdmissionClosed: () =>\n Effect.fail(ScheduledInputRetryable.make({ reason: \"host-closed\" })),\n AgentInputError: () => Effect.fail(corrupt(\"prepared admission input\")),\n AdmissionConflict: () => Effect.fail(corrupt(\"prepared admission conflict\")),\n DigestError: () => Effect.fail(ambiguous()),\n AdmissionPolicyError: (error) =>\n error.reason === \"refused\"\n ? ScheduledInputRefused.make({ code: error.code })\n : ScheduledInputRetryable.make({\n reason: error.reason === \"occupied\" ? \"capacity\" : \"storage\",\n }),\n LedgerError: () => ScheduledInputRetryable.make({ reason: \"storage\" }),\n ThreadStoreError: () => Effect.fail(ambiguous()),\n ThreadNotMaterialized: () => Effect.fail(ambiguous()),\n AppendConflict: () => Effect.fail(ambiguous()),\n FenceRejected: () => Effect.fail(ambiguous()),\n DurableRuntimeFailpointError: () => Effect.fail(ambiguous()),\n }),\n ),\n });\n }),\n);\n\nconst preparedFromSchedule = (envelope: ScheduledEnvelope): PreparedInput => ({\n schemaVersion: 1,\n threadId: envelope.threadId,\n deliveryPrincipal: envelope.deliveryPrincipal,\n ...(envelope.admissionGroup === undefined ? {} : { admissionGroup: envelope.admissionGroup }),\n ...(envelope.admissionFence === undefined ? {} : { admissionFence: envelope.admissionFence }),\n agentId: envelope.agentId,\n definitions: envelope.definitions,\n input: envelope.input,\n inputDigest: envelope.inputDigest,\n admissionKey: envelope.admissionKey,\n authorization: envelope.authorization,\n});\n\n/** Compatibility adapter retaining the public scheduling admission port. */\nconst nodeScheduledInputAdmissionFromPreparedLayer: Layer.Layer<\n ScheduledInputAdmission,\n never,\n PreparedInputAdmission\n> = Layer.effect(\n ScheduledInputAdmission,\n Effect.map(PreparedInputAdmission, (admission) =>\n ScheduledInputAdmission.of({\n submit: (envelope) => admission.submit(preparedFromSchedule(envelope)),\n }),\n ),\n);\n\nexport const nodeScheduledInputAdmissionLayer: Layer.Layer<\n ScheduledInputAdmission,\n never,\n NodeDurableHost\n> = nodeScheduledInputAdmissionFromPreparedLayer.pipe(\n Layer.provide(nodePreparedInputAdmissionLayer),\n);\n\nconst reportPassFailure = (cause: Cause.Cause<SubscriptionStoreFailure>): Effect.Effect<boolean> =>\n Cause.hasInterruptsOnly(cause)\n ? Effect.interrupt\n : Effect.logWarning(\"Node subscription pass failed\").pipe(\n Effect.annotateLogs({\n failureTag: Option.match(Cause.findErrorOption(cause), {\n onNone: () => \"Defect\",\n onSome: (error) => error._tag,\n }),\n }),\n Effect.as(false),\n );\n\nconst nodeSubscriptionDriverLayer = (\n limits: SubscriptionLimits,\n): Layer.Layer<never, never, SubscriptionDriver | SubscriptionStore> =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n const driver = yield* SubscriptionDriver;\n const store = yield* SubscriptionStore;\n\n const run = Effect.gen(function* () {\n while (true) {\n const passSucceeded = yield* driver.runDue.pipe(\n Effect.map((pass) => pass.failed === 0),\n Effect.catchCause(reportPassFailure),\n );\n\n if (!passSucceeded) {\n yield* Effect.sleep(Duration.millis(limits.retryMillis));\n continue;\n }\n\n const deadline = yield* store.nextDeadline.pipe(Effect.exit);\n\n if (Exit.isFailure(deadline)) {\n yield* reportPassFailure(deadline.cause);\n yield* Effect.sleep(Duration.millis(limits.retryMillis));\n continue;\n }\n\n const nowMillis = yield* Effect.clockWith((clock) => clock.currentTimeMillis);\n\n const delay =\n deadline.value === null\n ? limits.retryMillis\n : Math.max(1, Math.min(deadline.value - nowMillis, limits.retryMillis));\n\n yield* Effect.sleep(Duration.millis(delay));\n }\n });\n\n yield* Effect.forkScoped(run);\n }),\n );\n\nexport interface NodeSubscriptionsOptions {\n readonly limits?: SubscriptionLimits | undefined;\n}\n\n/**\n * One Scope-owned subscription partition in the sole process owning its SQLite database.\n * Indexed polling repairs restart and lost wake state; closing the Scope interrupts the driver.\n */\nexport class NodeSubscriptions {\n static layer(\n options: NodeSubscriptionsOptions = {},\n ): Layer.Layer<\n Subscriptions | SubscriptionIntake,\n SubscriptionError,\n | NodeDurableHost\n | SubscriptionStore\n | SubscriptionAuthorizer\n | EventSources\n | SubscriptionInputBindings\n > {\n const limits = options.limits ?? defaultSubscriptionLimits;\n\n const publicServices = Layer.merge(\n Subscriptions.layer(limits),\n SubscriptionIntake.layer(limits),\n );\n\n const driver = nodeSubscriptionDriverLayer(limits).pipe(\n Layer.provide(SubscriptionDriver.layer(limits)),\n );\n\n return Layer.merge(publicServices, driver).pipe(\n Layer.provide(nodePreparedInputAdmissionLayer),\n Layer.provide(NodeCrypto.layer),\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"NodeSubscriptions.mjs","names":[],"sources":["../src/NodeSubscriptions.ts"],"sourcesContent":["import { type EventSources } from \"@effect-agent/thread/EventSource\";\nimport { PreparedInputAdmission } from \"@effect-agent/thread/PreparedInputAdmission\";\nimport { type ScheduledEnvelope, ScheduledInputAdmission } from \"@effect-agent/thread/Schedule\";\nimport {\n type PreparedInput,\n type SubscriptionAuthorizer,\n type SubscriptionError,\n type SubscriptionLimits,\n type SubscriptionStoreFailure,\n SubscriptionStore,\n defaultSubscriptionLimits,\n} from \"@effect-agent/thread/Subscription\";\nimport { type SubscriptionInputBindings } from \"@effect-agent/thread/SubscriptionInput\";\nimport {\n SubscriptionDriver,\n SubscriptionIntake,\n Subscriptions,\n} from \"@effect-agent/thread/Subscriptions\";\nimport { NodeCrypto } from \"@effect/platform-node\";\nimport { Cause, Duration, Effect, Exit, Layer, Option } from \"effect\";\n\nimport { makeNodePreparedInputAdmission, NodeAdmission } from \"./internal/prepared-admission.ts\";\nimport { NodeDurableHost } from \"./NodeDurableHost.ts\";\n\n/** Ordinary prepared admission through the Scope-owned Node host gate. */\nexport const nodePreparedInputAdmissionLayer: Layer.Layer<\n PreparedInputAdmission,\n never,\n NodeDurableHost\n> = Layer.effect(PreparedInputAdmission, makeNodePreparedInputAdmission).pipe(\n Layer.provide(Layer.effect(NodeAdmission, NodeDurableHost)),\n);\n\nconst preparedFromSchedule = (envelope: ScheduledEnvelope): PreparedInput => ({\n schemaVersion: 1,\n threadId: envelope.threadId,\n deliveryPrincipal: envelope.deliveryPrincipal,\n ...(envelope.admissionGroup === undefined ? {} : { admissionGroup: envelope.admissionGroup }),\n ...(envelope.admissionFence === undefined ? {} : { admissionFence: envelope.admissionFence }),\n agentId: envelope.agentId,\n definitions: envelope.definitions,\n input: envelope.input,\n inputDigest: envelope.inputDigest,\n admissionKey: envelope.admissionKey,\n authorization: envelope.authorization,\n});\n\n/** Compatibility adapter retaining the public scheduling admission port. */\nconst nodeScheduledInputAdmissionFromPreparedLayer: Layer.Layer<\n ScheduledInputAdmission,\n never,\n PreparedInputAdmission\n> = Layer.effect(\n ScheduledInputAdmission,\n Effect.map(PreparedInputAdmission, (admission) =>\n ScheduledInputAdmission.of({\n submit: (envelope) => admission.submit(preparedFromSchedule(envelope)),\n }),\n ),\n);\n\nexport const nodeScheduledInputAdmissionLayer: Layer.Layer<\n ScheduledInputAdmission,\n never,\n NodeDurableHost\n> = nodeScheduledInputAdmissionFromPreparedLayer.pipe(\n Layer.provide(nodePreparedInputAdmissionLayer),\n);\n\nconst reportPassFailure = (cause: Cause.Cause<SubscriptionStoreFailure>): Effect.Effect<boolean> =>\n Cause.hasInterruptsOnly(cause)\n ? Effect.interrupt\n : Effect.logWarning(\"Node subscription pass failed\").pipe(\n Effect.annotateLogs({\n failureTag: Option.match(Cause.findErrorOption(cause), {\n onNone: () => \"Defect\",\n onSome: (error) => error._tag,\n }),\n }),\n Effect.as(false),\n );\n\nconst nodeSubscriptionDriverLayer = (\n limits: SubscriptionLimits,\n): Layer.Layer<never, never, SubscriptionDriver | SubscriptionStore> =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n const driver = yield* SubscriptionDriver;\n const store = yield* SubscriptionStore;\n\n const run = Effect.gen(function* () {\n while (true) {\n const passSucceeded = yield* driver.runDue.pipe(\n Effect.map((pass) => pass.failed === 0),\n Effect.catchCause(reportPassFailure),\n );\n\n if (!passSucceeded) {\n yield* Effect.sleep(Duration.millis(limits.retryMillis));\n continue;\n }\n\n const deadline = yield* store.nextDeadline.pipe(Effect.exit);\n\n if (Exit.isFailure(deadline)) {\n yield* reportPassFailure(deadline.cause);\n yield* Effect.sleep(Duration.millis(limits.retryMillis));\n continue;\n }\n\n const nowMillis = yield* Effect.clockWith((clock) => clock.currentTimeMillis);\n\n const delay =\n deadline.value === null\n ? limits.retryMillis\n : Math.max(1, Math.min(deadline.value - nowMillis, limits.retryMillis));\n\n yield* Effect.sleep(Duration.millis(delay));\n }\n });\n\n yield* Effect.forkScoped(run);\n }),\n );\n\nexport interface NodeSubscriptionsOptions {\n readonly limits?: SubscriptionLimits | undefined;\n}\n\n/**\n * One Scope-owned subscription partition in the sole process owning its SQLite database.\n * Indexed polling repairs restart and lost wake state; closing the Scope interrupts the driver.\n */\nexport class NodeSubscriptions {\n static layer(\n options: NodeSubscriptionsOptions = {},\n ): Layer.Layer<\n Subscriptions | SubscriptionIntake,\n SubscriptionError,\n | NodeDurableHost\n | SubscriptionStore\n | SubscriptionAuthorizer\n | EventSources\n | SubscriptionInputBindings\n > {\n const limits = options.limits ?? defaultSubscriptionLimits;\n\n const publicServices = Layer.merge(\n Subscriptions.layer(limits),\n SubscriptionIntake.layer(limits),\n );\n\n const driver = nodeSubscriptionDriverLayer(limits).pipe(\n Layer.provide(SubscriptionDriver.layer(limits)),\n );\n\n return Layer.merge(publicServices, driver).pipe(\n Layer.provide(nodePreparedInputAdmissionLayer),\n Layer.provide(NodeCrypto.layer),\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,MAAa,kCAIT,MAAM,OAAO,wBAAwB,8BAA8B,CAAC,CAAC,KACvE,MAAM,QAAQ,MAAM,OAAO,eAAe,eAAe,CAAC,CAC5D;AAEA,MAAM,wBAAwB,cAAgD;CAC5E,eAAe;CACf,UAAU,SAAS;CACnB,mBAAmB,SAAS;CAC5B,GAAI,SAAS,mBAAmB,KAAA,IAAY,CAAC,IAAI,EAAE,gBAAgB,SAAS,eAAe;CAC3F,GAAI,SAAS,mBAAmB,KAAA,IAAY,CAAC,IAAI,EAAE,gBAAgB,SAAS,eAAe;CAC3F,SAAS,SAAS;CAClB,aAAa,SAAS;CACtB,OAAO,SAAS;CAChB,aAAa,SAAS;CACtB,cAAc,SAAS;CACvB,eAAe,SAAS;AAC1B;AAgBA,MAAa,mCATT,MAAM,OACR,yBACA,OAAO,IAAI,yBAAyB,cAClC,wBAAwB,GAAG,EACzB,SAAS,aAAa,UAAU,OAAO,qBAAqB,QAAQ,CAAC,EACvE,CAAC,CACH,CAOE,CAAA,CAA6C,KAC/C,MAAM,QAAQ,+BAA+B,CAC/C;AAEA,MAAM,qBAAqB,UACzB,MAAM,kBAAkB,KAAK,IACzB,OAAO,YACP,OAAO,WAAW,+BAA+B,CAAC,CAAC,KACjD,OAAO,aAAa,EAClB,YAAY,OAAO,MAAM,MAAM,gBAAgB,KAAK,GAAG;CACrD,cAAc;CACd,SAAS,UAAU,MAAM;AAC3B,CAAC,EACH,CAAC,GACD,OAAO,GAAG,KAAK,CACjB;AAEN,MAAM,+BACJ,WAEA,MAAM,cACJ,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO;CACtB,MAAM,QAAQ,OAAO;CAErB,MAAM,MAAM,OAAO,IAAI,aAAa;EAClC,OAAO,MAAM;GAMX,IAAI,EAAC,OALwB,OAAO,OAAO,KACzC,OAAO,KAAK,SAAS,KAAK,WAAW,CAAC,GACtC,OAAO,WAAW,iBAAiB,CACrC,IAEoB;IAClB,OAAO,OAAO,MAAM,SAAS,OAAO,OAAO,WAAW,CAAC;IACvD;GACF;GAEA,MAAM,WAAW,OAAO,MAAM,aAAa,KAAK,OAAO,IAAI;GAE3D,IAAI,KAAK,UAAU,QAAQ,GAAG;IAC5B,OAAO,kBAAkB,SAAS,KAAK;IACvC,OAAO,OAAO,MAAM,SAAS,OAAO,OAAO,WAAW,CAAC;IACvD;GACF;GAEA,MAAM,YAAY,OAAO,OAAO,WAAW,UAAU,MAAM,iBAAiB;GAE5E,MAAM,QACJ,SAAS,UAAU,OACf,OAAO,cACP,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,QAAQ,WAAW,OAAO,WAAW,CAAC;GAE1E,OAAO,OAAO,MAAM,SAAS,OAAO,KAAK,CAAC;EAC5C;CACF,CAAC;CAED,OAAO,OAAO,WAAW,GAAG;AAC9B,CAAC,CACH;;;;;AAUF,IAAa,oBAAb,MAA+B;CAC7B,OAAO,MACL,UAAoC,CAAC,GASrC;EACA,MAAM,SAAS,QAAQ,UAAU;EAEjC,MAAM,iBAAiB,MAAM,MAC3B,cAAc,MAAM,MAAM,GAC1B,mBAAmB,MAAM,MAAM,CACjC;EAEA,MAAM,SAAS,4BAA4B,MAAM,CAAC,CAAC,KACjD,MAAM,QAAQ,mBAAmB,MAAM,MAAM,CAAC,CAChD;EAEA,OAAO,MAAM,MAAM,gBAAgB,MAAM,CAAC,CAAC,KACzC,MAAM,QAAQ,+BAA+B,GAC7C,MAAM,QAAQ,WAAW,KAAK,CAChC;CACF;AACF"}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as NodeWakeScheduler_d_exports } from "./NodeWakeScheduler-4ZeXYwPu.mjs";
2
- import { s as NodeDurableAgentRuntime_d_exports } from "./NodeDurableAgentRuntime-CPmWN-L_.mjs";
2
+ import { s as NodeDurableAgentRuntime_d_exports } from "./NodeDurableAgentRuntime-CFElFzNF.mjs";
3
3
  import { t as NodeDurableHost_d_exports } from "./NodeDurableHost.mjs";
4
4
  import { t as NodeScheduling_d_exports } from "./NodeScheduling.mjs";
5
5
  import { t as NodeSubscriptions_d_exports } from "./NodeSubscriptions.mjs";
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as NodeWakeScheduler_exports } from "./NodeWakeScheduler.mjs";
2
2
  import { t as NodeDurableAgentRuntime_exports } from "./NodeDurableAgentRuntime.mjs";
3
- import { t as NodeDurableHost_exports } from "./NodeDurableHost.mjs";
3
+ import { r as NodeDurableHost_exports } from "./NodeDurableHost-BMSajuQn.mjs";
4
4
  import { t as NodeSubscriptions_exports } from "./NodeSubscriptions.mjs";
5
5
  import { t as NodeScheduling_exports } from "./NodeScheduling.mjs";
6
6
  export { NodeDurableAgentRuntime_exports as NodeDurableAgentRuntime, NodeDurableHost_exports as NodeDurableHost, NodeScheduling_exports as NodeScheduling, NodeSubscriptions_exports as NodeSubscriptions, NodeWakeScheduler_exports as NodeWakeScheduler };
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@effect-agent/platform-node","version":"0.1.0-beta.56","dependencies":{"@effect-agent/core":"0.1.0-beta.56","@effect-agent/engine":"0.1.0-beta.56","@effect-agent/storage-sqlite":"0.1.0-beta.56","@effect-agent/thread":"0.1.0-beta.56","@effect-agent/workflow":"0.1.0-beta.56","@effect/platform-node":"4.0.0-rc.112","@effect/sql-sqlite-node":"4.0.0-rc.112"},"devDependencies":{"@effect-agent/capabilities":"0.1.0-beta.56","@effect/vitest":"4.0.0-rc.112","effect":"4.0.0-rc.112","typescript":"7.0.2","vite-plus":"0.3.0"},"peerDependencies":{"effect":"^4.0.0-rc.112"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./NodeDurableAgentRuntime":{"types":"./dist/NodeDurableAgentRuntime.d.mts","default":"./dist/NodeDurableAgentRuntime.mjs"},"./NodeDurableHost":{"types":"./dist/NodeDurableHost.d.mts","default":"./dist/NodeDurableHost.mjs"},"./NodeScheduling":{"types":"./dist/NodeScheduling.d.mts","default":"./dist/NodeScheduling.mjs"},"./NodeSubscriptions":{"types":"./dist/NodeSubscriptions.d.mts","default":"./dist/NodeSubscriptions.mjs"},"./NodeWakeScheduler":{"types":"./dist/NodeWakeScheduler.d.mts","default":"./dist/NodeWakeScheduler.mjs"},"./NodeWorkflow":{"types":"./dist/NodeWorkflow.d.mts","default":"./dist/NodeWorkflow.mjs"}},"description":"Class DN layer assembly for Effect Agent: the durable Node/SQLite runtime host, wake scheduler, and ownership drain.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/danieljvdm/effect-agent.git","directory":"packages/platform-node"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
1
+ {"name":"@effect-agent/platform-node","version":"0.1.0-beta.58","dependencies":{"@effect-agent/core":"0.1.0-beta.58","@effect-agent/engine":"0.1.0-beta.58","@effect-agent/storage-sqlite":"0.1.0-beta.58","@effect-agent/thread":"0.1.0-beta.58","@effect-agent/workflow":"0.1.0-beta.58","@effect/platform-node":"4.0.0-rc.112","@effect/sql-sqlite-node":"4.0.0-rc.112"},"devDependencies":{"@effect-agent/capabilities":"0.1.0-beta.58","@effect/vitest":"4.0.0-rc.112","effect":"4.0.0-rc.112","typescript":"7.0.2","vite-plus":"0.3.0"},"peerDependencies":{"effect":"^4.0.0-rc.112"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./NodeDurableAgentRuntime":{"types":"./dist/NodeDurableAgentRuntime.d.mts","default":"./dist/NodeDurableAgentRuntime.mjs"},"./NodeDurableHost":{"types":"./dist/NodeDurableHost.d.mts","default":"./dist/NodeDurableHost.mjs"},"./NodeScheduling":{"types":"./dist/NodeScheduling.d.mts","default":"./dist/NodeScheduling.mjs"},"./NodeSubscriptions":{"types":"./dist/NodeSubscriptions.d.mts","default":"./dist/NodeSubscriptions.mjs"},"./NodeWakeScheduler":{"types":"./dist/NodeWakeScheduler.d.mts","default":"./dist/NodeWakeScheduler.mjs"},"./NodeWorkflow":{"types":"./dist/NodeWorkflow.d.mts","default":"./dist/NodeWorkflow.mjs"}},"description":"Class DN layer assembly for Effect Agent: the durable Node/SQLite runtime host, wake scheduler, and ownership drain.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/danieljvdm/effect-agent.git","directory":"packages/platform-node"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
@@ -8,12 +8,16 @@ import {
8
8
  type RunCostEstimator,
9
9
  type RunToolFailureObserver,
10
10
  } from "@effect-agent/engine/RunOptions";
11
+ import { messageDeliveryStoreLayer } from "@effect-agent/storage-sqlite/SqliteMessageDeliveryStore";
11
12
  import { scheduleStoreLayer } from "@effect-agent/storage-sqlite/SqliteScheduleStore";
12
13
  import {
13
14
  SqliteStorageConfig,
14
15
  SqliteStorageConfigValue,
15
16
  } from "@effect-agent/storage-sqlite/SqliteStorageConfig";
16
- import { type SqliteStorageFailpointHandler } from "@effect-agent/storage-sqlite/SqliteStorageFailpoint";
17
+ import {
18
+ type SqliteStorageFailpoint,
19
+ type SqliteStorageFailpointHandler,
20
+ } from "@effect-agent/storage-sqlite/SqliteStorageFailpoint";
17
21
  import { submissionLedgerLayer } from "@effect-agent/storage-sqlite/SqliteSubmissionLedger";
18
22
  import {
19
23
  threadStoreLayer,
@@ -32,6 +36,10 @@ import {
32
36
  DurableRuntimeFailpoint,
33
37
  type DurableRuntimeFailpointHandler,
34
38
  } from "@effect-agent/thread/DurableFailpoint";
39
+ import {
40
+ type MessageDeliveryError,
41
+ type MessageDeliveryStore,
42
+ } from "@effect-agent/thread/MessageDelivery";
35
43
  import { DeploymentId, ProducerId } from "@effect-agent/thread/Records";
36
44
  import { type ScheduleStore } from "@effect-agent/thread/Schedule";
37
45
  import {
@@ -46,6 +54,7 @@ import { type WakeScheduler } from "@effect-agent/thread/WakeScheduler";
46
54
  import { NodeCrypto } from "@effect/platform-node";
47
55
  import { SqliteClient } from "@effect/sql-sqlite-node";
48
56
  import { Context, type Crypto, Duration, Effect, Layer, Ref, Schema } from "effect";
57
+ import type * as SqlClientService from "effect/unstable/sql/SqlClient";
49
58
 
50
59
  import { NodeWakeSchedulerConfig, nodeWakeSchedulerLayer } from "./NodeWakeScheduler.ts";
51
60
 
@@ -74,7 +83,7 @@ export class NodePlatformConfigError extends Schema.TaggedError<NodePlatformConf
74
83
  export class NodeDurableAgentRuntimeConfigValue extends Schema.Class<NodeDurableAgentRuntimeConfigValue>(
75
84
  "@effect-agent/platform-node/NodeDurableAgentRuntimeConfigValue",
76
85
  )({
77
- /** SQLite database file backing BOTH the Thread Log and the Submission Ledger. */
86
+ /** SQLite database file backing the Thread Log, Submission Ledger, and delivery obligations. */
78
87
  filename: Schema.NonEmptyString,
79
88
  deploymentId: DeploymentId,
80
89
  producerId: ProducerId,
@@ -82,7 +91,7 @@ export class NodeDurableAgentRuntimeConfigValue extends Schema.Class<NodeDurable
82
91
  ownershipLeaseDuration: PositiveMillis,
83
92
  /** Finite bound on concurrent worker loops per host (rule 10). */
84
93
  workerConcurrency: WorkerConcurrency,
85
- /** Ledger-scan fallback cadence of the Node wake scheduler (deployment §3). */
94
+ /** Fallback scan cadence for the Node wake scheduler and independent message delivery recovery. */
86
95
  wakeScanInterval: PositiveMillis,
87
96
  /** `awaitSettlement` ledger re-check cadence when no wake arrives. */
88
97
  settlementPollInterval: PositiveMillis,
@@ -177,17 +186,25 @@ export interface NodeDurableAgentRuntimeOptions<
177
186
  /** Built-in construction failures. `layer` also preserves supplied service Layers' errors. */
178
187
  export type NodeDurableAgentRuntimeInitializationError =
179
188
  | NodePlatformConfigError
189
+ | MessageDeliveryError
180
190
  | SqliteStorageInitializationError;
181
191
 
182
- /** The services `NodeDurableAgentRuntime.layer` provides. */
192
+ /**
193
+ * The services `NodeDurableAgentRuntime.layer` provides. Additional SQLite adapters can use
194
+ * the same client and storage configuration, sharing its serialized connection and Scope.
195
+ */
183
196
  export type NodeDurableAgentRuntimeServices =
184
197
  | DurableAgentRuntime
185
198
  | SubmissionLedger
186
199
  | ThreadStore
187
200
  | ScheduleStore
201
+ | MessageDeliveryStore
188
202
  | WakeScheduler
189
203
  | DurableRuntimeConfig
190
- | NodeDurableAgentRuntimeConfig;
204
+ | NodeDurableAgentRuntimeConfig
205
+ | SqlClientService.SqlClient
206
+ | SqliteStorageConfig
207
+ | SqliteStorageFailpoint;
191
208
 
192
209
  const decodeConfigValue = Schema.decodeUnknownEffect(NodeDurableAgentRuntimeConfigValue);
193
210
 
@@ -387,7 +404,8 @@ export const ownershipDrainLayer: Layer.Layer<SubmissionLedger, never, Submissio
387
404
  * The DN Layer assembly (deployment §12: a Layer-assembly library, not an app entrypoint).
388
405
  * `layer(options)` decodes the configuration, opens ONE SQLite database serving both the
389
406
  * Thread Log and the Submission Ledger (so claims fence the same producer epochs), wires
390
- * the Node wake scheduler with its ledger-scan fallback, wraps the ledger with the shutdown
407
+ * the Node wake scheduler with its ledger-scan fallback, exposes independent message delivery
408
+ * storage, wraps the ledger with the shutdown
391
409
  * ownership drain, defaults the Tool reconciliation policy to the fail-closed
392
410
  * `ToolReconciler.uncertain` (override via `options.toolReconciler`), and provides a ready
393
411
  * `DurableAgentRuntime` on top. Storage compatibility is
@@ -537,6 +555,7 @@ export class NodeDurableAgentRuntime {
537
555
  const ports = Layer.mergeAll(
538
556
  threadStoreLayer,
539
557
  scheduleStoreLayer,
558
+ messageDeliveryStoreLayer(),
540
559
  nodeWakeSchedulerLayer.pipe(
541
560
  Layer.provideMerge(ownershipDrainLayer.pipe(Layer.provide(submissionLedgerLayer))),
542
561
  ),
@@ -27,7 +27,13 @@ import {
27
27
  type Receipt,
28
28
  type RecoveryReport,
29
29
  } from "@effect-agent/thread/DurableAgentRuntime";
30
+ import {
31
+ type MessageDeliveryStore,
32
+ MessageDeliveryDriver,
33
+ type MessageDeliveryError,
34
+ } from "@effect-agent/thread/MessageDelivery";
30
35
  import { type OperationDenied } from "@effect-agent/thread/OperationAuthorizer";
36
+ import { PreparedInputAdmission } from "@effect-agent/thread/PreparedInputAdmission";
31
37
  import { type CanonicalRecordEnvelope } from "@effect-agent/thread/Records";
32
38
  import {
33
39
  type AbortCommand,
@@ -38,8 +44,11 @@ import {
38
44
  type ThreadNotMaterialized,
39
45
  type ThreadStoreError,
40
46
  } from "@effect-agent/thread/ThreadStore";
47
+ import { NodeCrypto } from "@effect/platform-node";
41
48
  import { type Stream, Context, Effect, Fiber, Layer, Ref, Schema } from "effect";
42
49
 
50
+ import { runNodeMessageDeliveries } from "./internal/message-delivery.ts";
51
+ import { makeNodePreparedInputAdmission, NodeAdmission } from "./internal/prepared-admission.ts";
43
52
  import {
44
53
  NodeDurableAgentRuntime,
45
54
  NodeDurableAgentRuntimeConfig,
@@ -88,11 +97,40 @@ const makeHost = Effect.fn("NodeDurableHost.make")(function* (startWorkers: bool
88
97
  InputSchema["EncodingServices"]
89
98
  > => requireAdmission.pipe(Effect.andThen(runtime.submit(agent, input, options)));
90
99
 
100
+ const deliveryServices = yield* Effect.context<MessageDeliveryStore>();
101
+
102
+ const deliveryContext = yield* Layer.build(
103
+ MessageDeliveryDriver.layer({
104
+ batchSize: 100,
105
+ concurrency: Math.min(config.workerConcurrency, 32),
106
+ }).pipe(
107
+ Layer.provide(NodeCrypto.layer),
108
+ Layer.provide(
109
+ Layer.effect(PreparedInputAdmission, makeNodePreparedInputAdmission).pipe(
110
+ Layer.provide(
111
+ Layer.succeed(NodeAdmission, { submit, submissionStatus: runtime.submissionStatus }),
112
+ ),
113
+ ),
114
+ ),
115
+ ),
116
+ );
117
+
118
+ const runDeliveries = runNodeMessageDeliveries(config.wakeScanInterval).pipe(
119
+ Effect.provide(Context.merge(deliveryServices, deliveryContext)),
120
+ );
121
+
91
122
  const runWorkers = <A, E, R>(worker: Effect.Effect<A, E, R>): Effect.Effect<void, E, R> =>
92
- Effect.forEach(
93
- Array.from({ length: config.workerConcurrency }, (_, index) => index),
94
- () => worker,
95
- { concurrency: "unbounded", discard: true },
123
+ Effect.scoped(
124
+ // Either side exiting stops and joins the other; delivery interruption cannot leave
125
+ // an apparently healthy worker pool running without message recovery.
126
+ Effect.raceFirst(
127
+ Effect.forEach(
128
+ Array.from({ length: config.workerConcurrency }, (_, index) => index),
129
+ () => worker,
130
+ { concurrency: "unbounded", discard: true },
131
+ ),
132
+ runDeliveries,
133
+ ),
96
134
  );
97
135
 
98
136
  // S2 multi-binding pool: every claimed head resolves its exact registered Binding through
@@ -203,7 +241,8 @@ export class NodeDurableHost extends Context.Service<
203
241
  /**
204
242
  * Run `workerConcurrency` copies of the given worker effect (typically
205
243
  * `DurableAgentRuntime.runWorker(agent)`) until the caller's Scope interrupts them. The
206
- * bound is the validated finite configuration value; the host never forks daemon fibers.
244
+ * same Scope drives pending message admission and settlement observation independently
245
+ * of Submission liveness. The host never forks daemon fibers.
207
246
  */
208
247
  readonly runWorkers: <A, E, R>(worker: Effect.Effect<A, E, R>) => Effect.Effect<void, E, R>;
209
248
  /**
@@ -251,8 +290,8 @@ export class NodeDurableHost extends Context.Service<
251
290
  */
252
291
  static readonly layer: Layer.Layer<
253
292
  NodeDurableHost,
254
- DurableWorkerFailure,
255
- DurableAgentRuntime | NodeDurableAgentRuntimeConfig
293
+ DurableWorkerFailure | MessageDeliveryError,
294
+ DurableAgentRuntime | NodeDurableAgentRuntimeConfig | MessageDeliveryStore
256
295
  > = Layer.effect(NodeDurableHost)(makeHost(false));
257
296
 
258
297
  /** The complete DN host: `NodeDurableAgentRuntime.layer(options)` plus the host lifecycle gates. */