@effect-agent/platform-node 0.1.0-beta.37 → 0.1.0-beta.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,8 +1,8 @@
1
- import { AbortCommand, AbortIntent, AgentBindingResolver, CanonicalRecordEnvelope, ConversationNotMaterialized, ConversationStore, ConversationStoreError, DurableAbortFailure, DurableAgentRuntime, DurableAwaitFailure, DurableBindingFailure, DurableExplainFailure, DurableObligationFailure, DurableObserveOptions, DurableRetryFailure, DurableRuntimeConfig, DurableRuntimeFailpointHandler, DurableSubmitAgent, DurableSubmitFailure, DurableSubmitOptions, DurableVerifyFailure, DurableWorkerFailure, IntegrityReport, ObligationReport, ObligationThresholds, OperationDenied, Receipt, RecoveryExplanation, RecoveryReport, ResolvedBinding, RetryCommand, ScheduleAuthorizer, ScheduleStore, ScheduleValidationError, ScheduleWake, ScheduledInputAdmission, Scheduling, SchedulingLimits, Settlement, SubmissionLedger, ToolReconciler, WakeScheduler } from "@effect-agent/session";
2
- import { Context, Duration, Effect, Layer, Schema, Stream } from "effect";
3
- import { RunCostEstimator, RunToolFailureObserver } from "@effect-agent/engine";
1
+ import { AbortCommand, AbortIntent, CanonicalRecordEnvelope, DurableAbortFailure, DurableAgentRuntime, DurableAwaitFailure, DurableBindingFailure, DurableExplainFailure, DurableObligationFailure, DurableObserveOptions, DurableRetryFailure, DurableRuntimeConfig, DurableRuntimeFailpointHandler, DurableSubmitAgent, DurableSubmitFailure, DurableSubmitOptions, DurableVerifyFailure, DurableWorkerFailure, EventSources, IntegrityReport, ObligationReport, ObligationThresholds, OperationDenied, PreparedInputAdmission, Receipt, RecoveryExplanation, RecoveryReport, ResolvedBinding, RetryCommand, ScheduleAuthorizer, ScheduleStore, ScheduleValidationError, ScheduleWake, ScheduledInputAdmission, Scheduling, SchedulingLimits, Settlement, SubmissionLedger, SubscriptionAuthorizer, SubscriptionError, SubscriptionInputBindings, SubscriptionIntake, SubscriptionLimits, SubscriptionStore, Subscriptions, ThreadNotMaterialized, ThreadStore, ThreadStoreError, ToolReconciler, WakeScheduler } from "@effect-agent/thread";
2
+ import { Context, Crypto, Duration, Effect, Layer, Schema, Stream } from "effect";
3
+ import { RunContextPreparation, RunCostEstimator, RunToolAuthorization, RunToolFailureObserver } from "@effect-agent/engine";
4
4
  import { SqliteStorageFailpointHandler, SqliteStorageInitializationError } from "@effect-agent/storage-sqlite";
5
- import { ConversationId, SubmissionId } from "@effect-agent/core";
5
+ import { SubmissionId, ThreadId } from "@effect-agent/core";
6
6
  //#region src/layers.d.ts
7
7
  declare const NodePlatformConfigError_base: Schema.Class<NodePlatformConfigError, Schema.TaggedStruct<"NodePlatformConfigError", {
8
8
  readonly message: Schema.String;
@@ -11,10 +11,10 @@ declare const NodePlatformConfigError_base: Schema.Class<NodePlatformConfigError
11
11
  /** The supplied Node durable runtime configuration failed schema validation (DEPLOY-003). */
12
12
  declare class NodePlatformConfigError extends NodePlatformConfigError_base {}
13
13
  declare const NodeDurableRuntimeConfigValue_base: Schema.Class<NodeDurableRuntimeConfigValue, Schema.Struct<{
14
- /** SQLite database file backing BOTH the Conversation Log and the Submission Ledger. */
14
+ /** SQLite database file backing BOTH the Thread Log and the Submission Ledger. */
15
15
  readonly filename: Schema.NonEmptyString;
16
- readonly deploymentId: Schema.brand<Schema.NonEmptyString, "@effect-agent/session/DeploymentId">;
17
- readonly producerId: Schema.brand<Schema.NonEmptyString, "@effect-agent/session/ProducerId">;
16
+ readonly deploymentId: Schema.brand<Schema.NonEmptyString, "@effect-agent/thread/DeploymentId">;
17
+ readonly producerId: Schema.brand<Schema.NonEmptyString, "@effect-agent/thread/ProducerId">;
18
18
  /** Submission ownership lease duration (D5); liveness hint only, epochs stay authoritative. */
19
19
  readonly ownershipLeaseDuration: Schema.Int;
20
20
  /** Finite bound on concurrent worker loops per host (rule 10). */
@@ -48,7 +48,7 @@ declare class NodeDurableRuntimeConfig extends NodeDurableRuntimeConfig_base {}
48
48
  * to the documented production values; everything is schema-decoded into
49
49
  * `NodeDurableRuntimeConfigValue` before any resource opens (deployment §5 gate 1).
50
50
  */
51
- interface NodeDurableRuntimeOptions {
51
+ interface NodeDurableRuntimeOptions<ContextError = never, ContextRequirements = never, AuthorizationError = never, AuthorizationRequirements = never> {
52
52
  readonly filename: string;
53
53
  readonly deploymentId: string;
54
54
  readonly producerId: string;
@@ -85,20 +85,19 @@ interface NodeDurableRuntimeOptions {
85
85
  * DUR-017 resolution path.
86
86
  */
87
87
  readonly toolReconciler?: Layer.Layer<ToolReconciler> | undefined;
88
+ /** Host prompt preparation/compaction, acquired once with the runtime; default pass-through. */
89
+ readonly runContext?: Layer.Layer<RunContextPreparation, ContextError, ContextRequirements | Crypto.Crypto> | undefined;
88
90
  /**
89
- * Registered worker Bindings resolved at durable claim time:
90
- * build each with `DurableWorkerBinding.make(binding, digests)` so
91
- * `NodeDurableHost.runResolvedWorkers` / `DurableAgentRuntime.runResolvedWorker` can serve
92
- * parent and child lanes from one pool with exact-digest resolution (SUB-023). Defaults to
93
- * the empty registration: every resolved claim then fails closed (`BindingUnavailable` for a
94
- * root, the framework `ChildCompatibilityFailure` Settlement for a parent-linked child).
91
+ * Independent action-time Tool authority, acquired once with the runtime; default allow-all.
92
+ * Construction errors and application dependencies remain in the assembled Layer's E and R.
93
+ * The platform supplies Crypto to both extension Layers.
95
94
  */
96
- readonly bindings?: ReadonlyArray<ResolvedBinding> | undefined;
95
+ readonly toolAuthorization?: Layer.Layer<RunToolAuthorization, AuthorizationError, AuthorizationRequirements | Crypto.Crypto> | undefined;
97
96
  }
98
- /** Every construction failure of the assembled Node durable runtime stack. */
97
+ /** Built-in construction failures. `layer` also preserves supplied service Layers' errors. */
99
98
  type NodeDurableRuntimeInitializationError = NodePlatformConfigError | SqliteStorageInitializationError;
100
99
  /** The services `NodeDurableRuntime.layer` provides. */
101
- type NodeDurableRuntimeServices = DurableAgentRuntime | SubmissionLedger | ConversationStore | ScheduleStore | WakeScheduler | DurableRuntimeConfig | NodeDurableRuntimeConfig | AgentBindingResolver;
100
+ type NodeDurableRuntimeServices = DurableAgentRuntime | SubmissionLedger | ThreadStore | ScheduleStore | WakeScheduler | DurableRuntimeConfig | NodeDurableRuntimeConfig;
102
101
  /**
103
102
  * Shutdown-drain decorator for a `SubmissionLedger` (deployment §6 step 6): every ownership
104
103
  * period granted through this Layer is tracked — claims start tracking, renewals follow token
@@ -111,7 +110,7 @@ declare const ownershipDrainLayer: Layer.Layer<SubmissionLedger, never, Submissi
111
110
  /**
112
111
  * The DN Layer assembly (deployment §12: a Layer-assembly library, not an app entrypoint).
113
112
  * `layer(options)` decodes the configuration, opens ONE SQLite database serving both the
114
- * Conversation Log and the Submission Ledger (so claims fence the same producer epochs), wires
113
+ * Thread Log and the Submission Ledger (so claims fence the same producer epochs), wires
115
114
  * the Node wake scheduler with its ledger-scan fallback, wraps the ledger with the shutdown
116
115
  * ownership drain, defaults the Tool reconciliation policy to the fail-closed
117
116
  * `ToolReconciler.uncertain` (override via `options.toolReconciler`), and provides a ready
@@ -121,9 +120,9 @@ declare const ownershipDrainLayer: Layer.Layer<SubmissionLedger, never, Submissi
121
120
  */
122
121
  declare class NodeDurableRuntime {
123
122
  /** Validated configuration Layer; fails typed when the supplied options are out of bounds. */
124
- static configLayer(options: NodeDurableRuntimeOptions): Layer.Layer<NodeDurableRuntimeConfig, NodePlatformConfigError>;
123
+ static configLayer<ContextError = never, ContextRequirements = never, AuthorizationError = never, AuthorizationRequirements = never>(options: NodeDurableRuntimeOptions<ContextError, ContextRequirements, AuthorizationError, AuthorizationRequirements>): Layer.Layer<NodeDurableRuntimeConfig, NodePlatformConfigError>;
125
124
  /** The full DN runtime stack over one SQLite file. */
126
- static layer(options: NodeDurableRuntimeOptions): Layer.Layer<NodeDurableRuntimeServices, NodeDurableRuntimeInitializationError>;
125
+ static layer<ContextError = never, ContextRequirements = never, AuthorizationError = never, AuthorizationRequirements = never>(options: NodeDurableRuntimeOptions<ContextError, ContextRequirements, AuthorizationError, AuthorizationRequirements>): Layer.Layer<NodeDurableRuntimeServices, NodeDurableRuntimeInitializationError | ContextError | AuthorizationError, Exclude<ContextRequirements | AuthorizationRequirements, Crypto.Crypto>>;
127
126
  }
128
127
  //#endregion
129
128
  //#region src/host.d.ts
@@ -147,18 +146,18 @@ declare const NodeDurableHost_base: Context.ServiceClass<NodeDurableHost, "@effe
147
146
  /** `DurableAgentRuntime.submit` behind the host admission gate. */
148
147
  readonly submit: <InputSchema extends Schema.Top>(agent: DurableSubmitAgent<InputSchema>, input: InputSchema["Type"], options: DurableSubmitOptions) => Effect.Effect<Receipt, AdmissionClosed | DurableSubmitFailure, InputSchema["EncodingServices"]>;
149
148
  readonly awaitSettlement: (receipt: Receipt) => Effect.Effect<Settlement, DurableAwaitFailure>;
150
- readonly observe: (receipt: Receipt, options?: DurableObserveOptions) => Stream.Stream<CanonicalRecordEnvelope, ConversationStoreError | ConversationNotMaterialized | OperationDenied>;
149
+ readonly observe: (receipt: Receipt, options?: DurableObserveOptions) => Stream.Stream<CanonicalRecordEnvelope, ThreadStoreError | ThreadNotMaterialized | OperationDenied>;
151
150
  readonly abort: (command: AbortCommand) => Effect.Effect<AbortIntent, DurableAbortFailure>;
152
151
  /** `DurableAgentRuntime.explain` — read-only recovery explanation of one Submission (P7). */
153
152
  readonly explain: (submissionId: SubmissionId) => Effect.Effect<RecoveryExplanation, DurableExplainFailure>;
154
- /** `DurableAgentRuntime.explainConversation` — explain every nonterminal lane member. */
155
- readonly explainConversation: (conversationId: ConversationId) => Effect.Effect<ReadonlyArray<RecoveryExplanation>, DurableExplainFailure>;
153
+ /** `DurableAgentRuntime.explainThread` — explain every nonterminal lane member. */
154
+ readonly explainThread: (threadId: ThreadId) => Effect.Effect<ReadonlyArray<RecoveryExplanation>, DurableExplainFailure>;
156
155
  /** `DurableAgentRuntime.verify` — read-only integrity checks, never a repair (P7). */
157
- readonly verify: (conversationId: ConversationId) => Effect.Effect<IntegrityReport, DurableVerifyFailure>;
156
+ readonly verify: (threadId: ThreadId) => Effect.Effect<IntegrityReport, DurableVerifyFailure>;
158
157
  /** `DurableAgentRuntime.retry` — audited single-Submission re-drive with typed refusals. */
159
158
  readonly retry: (command: RetryCommand) => Effect.Effect<RecoveryReport, DurableRetryFailure>;
160
159
  /** `DurableAgentRuntime.wake` — the documented operator liveness nudge for one lane. */
161
- readonly wake: (conversationId: ConversationId) => Effect.Effect<void, OperationDenied>;
160
+ readonly wake: (threadId: ThreadId) => Effect.Effect<void, OperationDenied>;
162
161
  /** `DurableAgentRuntime.scanObligations` — the scan-based DUR-017/OPS-001 report. */
163
162
  readonly scanObligations: (thresholds: ObligationThresholds) => Effect.Effect<ObligationReport, DurableObligationFailure>;
164
163
  /**
@@ -189,18 +188,18 @@ declare const NodeDurableHost_base: Context.ServiceClass<NodeDurableHost, "@effe
189
188
  * shutdown, provides correctness (DEPLOY-006).
190
189
  */
191
190
  declare class NodeDurableHost extends NodeDurableHost_base {
192
- /** Host gates over an already-assembled `NodeDurableRuntime` stack. */
193
- static readonly layer: Layer.Layer<NodeDurableHost, DurableWorkerFailure, DurableAgentRuntime | NodeDurableRuntimeConfig | AgentBindingResolver>;
191
+ /**
192
+ * Host gates over an assembled `NodeDurableRuntime` stack. Bindings must carry the exact
193
+ * digests stored by submitters. Omission registers no Agents, so resolved work fails closed.
194
+ */
195
+ static readonly layer: (bindings?: ReadonlyArray<ResolvedBinding>) => Layer.Layer<NodeDurableHost, DurableWorkerFailure, DurableAgentRuntime | NodeDurableRuntimeConfig>;
194
196
  /** The complete DN host: `NodeDurableRuntime.layer(options)` plus the host lifecycle gates. */
195
- static layerStack(options: NodeDurableRuntimeOptions): Layer.Layer<NodeDurableHost | NodeDurableRuntimeServices, DurableWorkerFailure | NodeDurableRuntimeInitializationError>;
197
+ static layerStack<ContextError = never, ContextRequirements = never, AuthorizationError = never, AuthorizationRequirements = never>(options: NodeDurableRuntimeOptions<ContextError, ContextRequirements, AuthorizationError, AuthorizationRequirements> & {
198
+ readonly bindings?: ReadonlyArray<ResolvedBinding>;
199
+ }): Layer.Layer<NodeDurableHost | NodeDurableRuntimeServices, DurableWorkerFailure | NodeDurableRuntimeInitializationError | ContextError | AuthorizationError, Exclude<ContextRequirements | AuthorizationRequirements, Crypto.Crypto>>;
196
200
  }
197
201
  //#endregion
198
202
  //#region src/scheduling.d.ts
199
- /**
200
- * Scheduled admission through the existing host gate. Once the gate admits the call, every
201
- * runtime failure stays ambiguous because the Submission may already have committed.
202
- */
203
- declare const nodeScheduledInputAdmissionLayer: Layer.Layer<ScheduledInputAdmission, never, NodeDurableHost>;
204
203
  /** One bounded hint slot for the single supported Node scheduler. Indexed polling repairs loss. */
205
204
  declare const nodeScheduleWakeLayer: Layer.Layer<ScheduleWake>;
206
205
  interface NodeSchedulingOptions {
@@ -214,9 +213,24 @@ declare class NodeScheduling {
214
213
  static layer(options?: NodeSchedulingOptions): Layer.Layer<Scheduling, ScheduleValidationError, NodeDurableHost | ScheduleStore | ScheduleAuthorizer>;
215
214
  }
216
215
  //#endregion
216
+ //#region src/subscriptions.d.ts
217
+ /** Ordinary prepared admission through the Scope-owned Node host gate. */
218
+ declare const nodePreparedInputAdmissionLayer: Layer.Layer<PreparedInputAdmission, never, NodeDurableHost>;
219
+ declare const nodeScheduledInputAdmissionLayer: Layer.Layer<ScheduledInputAdmission, never, NodeDurableHost>;
220
+ interface NodeSubscriptionsOptions {
221
+ readonly limits?: SubscriptionLimits | undefined;
222
+ }
223
+ /**
224
+ * One Scope-owned subscription partition in the sole process owning its SQLite database.
225
+ * Indexed polling repairs restart and lost wake state; closing the Scope interrupts the driver.
226
+ */
227
+ declare class NodeSubscriptions {
228
+ static layer(options?: NodeSubscriptionsOptions): Layer.Layer<Subscriptions | SubscriptionIntake, SubscriptionError, NodeDurableHost | SubscriptionStore | SubscriptionAuthorizer | EventSources | SubscriptionInputBindings>;
229
+ }
230
+ //#endregion
217
231
  //#region src/wake-scheduler.d.ts
218
232
  declare const NodeWakeSchedulerConfig_base: Context.ServiceClass<NodeWakeSchedulerConfig, "@effect-agent/platform-node/NodeWakeSchedulerConfig", {
219
- /** Interval between ledger scans that re-emit every nonterminal Conversation lane. */
233
+ /** Interval between ledger scans that re-emit every nonterminal Thread lane. */
220
234
  readonly scanInterval: Duration.Duration;
221
235
  }>;
222
236
  /** Cadence authority for the Node wake scheduler's ledger-scan fallback loop. */
@@ -234,5 +248,5 @@ declare class NodeWakeSchedulerConfig extends NodeWakeSchedulerConfig_base {
234
248
  */
235
249
  declare const nodeWakeSchedulerLayer: Layer.Layer<WakeScheduler, never, SubmissionLedger | NodeWakeSchedulerConfig>;
236
250
  //#endregion
237
- export { AdmissionClosed, NodeDurableHost, NodeDurableRuntime, NodeDurableRuntimeConfig, NodeDurableRuntimeConfigValue, NodeDurableRuntimeInitializationError, NodeDurableRuntimeOptions, NodeDurableRuntimeServices, NodePlatformConfigError, NodeScheduling, NodeSchedulingOptions, NodeWakeSchedulerConfig, nodeScheduleWakeLayer, nodeScheduledInputAdmissionLayer, nodeWakeSchedulerLayer, ownershipDrainLayer };
251
+ export { AdmissionClosed, NodeDurableHost, NodeDurableRuntime, NodeDurableRuntimeConfig, NodeDurableRuntimeConfigValue, NodeDurableRuntimeInitializationError, NodeDurableRuntimeOptions, NodeDurableRuntimeServices, NodePlatformConfigError, NodeScheduling, NodeSchedulingOptions, NodeSubscriptions, NodeSubscriptionsOptions, NodeWakeSchedulerConfig, nodePreparedInputAdmissionLayer, nodeScheduleWakeLayer, nodeScheduledInputAdmissionLayer, nodeWakeSchedulerLayer, ownershipDrainLayer };
238
252
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { AgentBindingResolver, DEFAULT_OWNERSHIP_LEASE_DURATION, DeploymentId, DurableAgentRuntime, DurableRuntimeConfig, DurableRuntimeFailpoint, PersistedJson, ProducerId, ReleaseOwnershipRequest, ScheduleDriver, ScheduleStorageError, ScheduleStore, ScheduleWake, ScheduledInputAdmission, ScheduledInputRetryable, Scheduling, SubmissionLedger, ToolReconciler, WakeScheduler, defaultSchedulingLimits, makeWakeSubscriptionHub } from "@effect-agent/session";
2
- import { Cause, Context, Duration, Effect, Layer, Option, PubSub, Ref, Result, Schema, Stream } from "effect";
3
- import { CurrentToolFailureObserver, toolFailureObserverLayer } from "@effect-agent/engine";
4
- import { SqliteStorageConfig, SqliteStorageConfigValue, conversationStoreLayer, scheduleStoreLayer, storageFailpointLayer, submissionLedgerLayer } from "@effect-agent/storage-sqlite";
1
+ import { DEFAULT_OWNERSHIP_LEASE_DURATION, DeploymentId, DurableAgentRuntime, DurableRuntimeConfig, DurableRuntimeFailpoint, PersistedJson, PreparedInputAdmission, ProducerId, ReleaseOwnershipRequest, ScheduleDriver, ScheduleStorageError, ScheduleStore, ScheduleWake, ScheduledInputAdmission, ScheduledInputRetryable, Scheduling, SubmissionLedger, SubscriptionDriver, SubscriptionIntake, SubscriptionStore, Subscriptions, ToolReconciler, WakeScheduler, defaultSchedulingLimits, defaultSubscriptionLimits, makeWakeSubscriptionHub } from "@effect-agent/thread";
2
+ import { Cause, Context, Duration, Effect, Exit, Layer, Option, PubSub, Ref, Result, Schema, Stream } from "effect";
3
+ import { CurrentToolFailureObserver, RunContextPreparationPassthrough, RunToolAuthorization, toolFailureObserverLayer } from "@effect-agent/engine";
4
+ import { SqliteStorageConfig, SqliteStorageConfigValue, scheduleStoreLayer, storageFailpointLayer, submissionLedgerLayer, threadStoreLayer } from "@effect-agent/storage-sqlite";
5
5
  import { NodeCrypto } from "@effect/platform-node";
6
6
  import { SqliteClient } from "@effect/sql-sqlite-node";
7
7
  //#region src/wake-scheduler.ts
@@ -23,13 +23,13 @@ const makeWakeScheduler = Effect.gen(function* () {
23
23
  const progress = yield* makeWakeSubscriptionHub;
24
24
  yield* Effect.addFinalizer(() => PubSub.shutdown(hints));
25
25
  /**
26
- * One fallback scan: every Conversation lane with nonterminal work, deduplicated. A scan
26
+ * One fallback scan: every Thread lane with nonterminal work, deduplicated. A scan
27
27
  * failure degrades to "no hints this round" — the wake channel has no error contract and the
28
28
  * next round retries — but is logged so a persistently failing ledger stays visible.
29
29
  */
30
30
  const scanOnce = Stream.runCollect(ledger.scanNonterminal).pipe(Effect.map((snapshots) => {
31
31
  const lanes = /* @__PURE__ */ new Set();
32
- for (const snapshot of snapshots) lanes.add(snapshot.conversationId);
32
+ for (const snapshot of snapshots) lanes.add(snapshot.threadId);
33
33
  return [...lanes];
34
34
  }), Effect.catch((error) => Effect.logWarning("NodeWakeScheduler fallback scan failed", error).pipe(Effect.as([]))));
35
35
  /**
@@ -39,7 +39,7 @@ const makeWakeScheduler = Effect.gen(function* () {
39
39
  */
40
40
  const fallbackScans = Stream.fromIterableEffectRepeat(Effect.sleep(config.scanInterval).pipe(Effect.andThen(scanOnce)));
41
41
  return WakeScheduler.of({
42
- notify: (conversationId) => progress.notify(conversationId).pipe(Effect.andThen(PubSub.publish(hints, conversationId)), Effect.asVoid),
42
+ notify: (threadId) => progress.notify(threadId).pipe(Effect.andThen(PubSub.publish(hints, threadId)), Effect.asVoid),
43
43
  subscribe: progress.subscribe,
44
44
  wakes: Stream.merge(Stream.fromPubSub(hints), fallbackScans)
45
45
  });
@@ -68,7 +68,7 @@ var NodePlatformConfigError = class extends Schema.TaggedError()("NodePlatformCo
68
68
  * finite; `workerConcurrency` caps how many worker loops `NodeDurableHost.runWorkers` drives.
69
69
  */
70
70
  var NodeDurableRuntimeConfigValue = class extends Schema.Class("@effect-agent/platform-node/NodeDurableRuntimeConfigValue")({
71
- /** SQLite database file backing BOTH the Conversation Log and the Submission Ledger. */
71
+ /** SQLite database file backing BOTH the Thread Log and the Submission Ledger. */
72
72
  filename: Schema.NonEmptyString,
73
73
  deploymentId: DeploymentId,
74
74
  producerId: ProducerId,
@@ -121,7 +121,7 @@ const sqliteStorageConfigLayer = Layer.effect(SqliteStorageConfig)(Effect.gen(fu
121
121
  verifyOnOpen: config.verifyOnOpen
122
122
  });
123
123
  }));
124
- /** Session coordinator configuration derived from the single validated Node configuration. */
124
+ /** Thread coordinator configuration derived from the single validated Node configuration. */
125
125
  const durableRuntimeConfigLayer = (estimateCostMicrousd) => Layer.effect(DurableRuntimeConfig)(Effect.gen(function* () {
126
126
  const config = yield* NodeDurableRuntimeConfig;
127
127
  return DurableRuntimeConfig.make({
@@ -198,7 +198,7 @@ const ownershipDrainLayer = Layer.effect(SubmissionLedger)(Effect.gen(function*
198
198
  /**
199
199
  * The DN Layer assembly (deployment §12: a Layer-assembly library, not an app entrypoint).
200
200
  * `layer(options)` decodes the configuration, opens ONE SQLite database serving both the
201
- * Conversation Log and the Submission Ledger (so claims fence the same producer epochs), wires
201
+ * Thread Log and the Submission Ledger (so claims fence the same producer epochs), wires
202
202
  * the Node wake scheduler with its ledger-scan fallback, wraps the ledger with the shutdown
203
203
  * ownership drain, defaults the Tool reconciliation policy to the fail-closed
204
204
  * `ToolReconciler.uncertain` (override via `options.toolReconciler`), and provides a ready
@@ -222,9 +222,8 @@ var NodeDurableRuntime = class {
222
222
  const runtimeFailpointLayer = options.runtimeFailpoint === void 0 ? DurableRuntimeFailpoint.layer : Layer.succeed(DurableRuntimeFailpoint)({ hit: options.runtimeFailpoint });
223
223
  const reconcilerLayer = options.toolReconciler ?? ToolReconciler.uncertain;
224
224
  const observerLayer = options.toolFailureObserver === void 0 ? Layer.succeed(CurrentToolFailureObserver)(void 0) : toolFailureObserverLayer(options.toolFailureObserver);
225
- const bindingResolverLayer = AgentBindingResolver.layer(options.bindings ?? []);
226
- const ports = Layer.mergeAll(conversationStoreLayer, scheduleStoreLayer, nodeWakeSchedulerLayer.pipe(Layer.provideMerge(ownershipDrainLayer.pipe(Layer.provide(submissionLedgerLayer)))));
227
- return DurableAgentRuntime.layer.pipe(Layer.provideMerge(Layer.mergeAll(ports, durableRuntimeConfigLayer(options.estimateCostMicrousd), bindingResolverLayer)), Layer.provide(Layer.mergeAll(wakeSchedulerConfigLayer, runtimeFailpointLayer, reconcilerLayer, observerLayer)), Layer.provideMerge(infrastructure), Layer.provideMerge(nodeConfigLayer));
225
+ const ports = Layer.mergeAll(threadStoreLayer, scheduleStoreLayer, nodeWakeSchedulerLayer.pipe(Layer.provideMerge(ownershipDrainLayer.pipe(Layer.provide(submissionLedgerLayer)))));
226
+ return DurableAgentRuntime.layerWithServices.pipe(Layer.provideMerge(Layer.mergeAll(ports, durableRuntimeConfigLayer(options.estimateCostMicrousd))), Layer.provide(Layer.mergeAll(wakeSchedulerConfigLayer, runtimeFailpointLayer, reconcilerLayer, observerLayer)), Layer.provideMerge(infrastructure), Layer.provideMerge(nodeConfigLayer), Layer.provide(Layer.mergeAll(options.runContext ?? RunContextPreparationPassthrough, options.toolAuthorization ?? RunToolAuthorization.allowAll).pipe(Layer.provide(NodeCrypto.layer))));
228
227
  }));
229
228
  }
230
229
  };
@@ -235,10 +234,9 @@ var NodeDurableRuntime = class {
235
234
  * Accepted work is unaffected — only NEW admissions are refused.
236
235
  */
237
236
  var AdmissionClosed = class extends Schema.TaggedError()("AdmissionClosed", { message: Schema.String }) {};
238
- const makeHost = Effect.gen(function* () {
237
+ const makeHost = (bindings) => Effect.gen(function* () {
239
238
  const runtime = yield* DurableAgentRuntime;
240
239
  const config = yield* NodeDurableRuntimeConfig;
241
- const bindingResolver = yield* AgentBindingResolver;
242
240
  const startupRecovery = yield* runtime.runRecovery;
243
241
  const admission = yield* Ref.make(true);
244
242
  yield* Effect.addFinalizer(() => Ref.set(admission, false));
@@ -248,7 +246,7 @@ const makeHost = Effect.gen(function* () {
248
246
  concurrency: "unbounded",
249
247
  discard: true
250
248
  });
251
- const runResolvedWorkers = runWorkers(runtime.runResolvedWorker.pipe(Effect.provideService(AgentBindingResolver, bindingResolver)));
249
+ const runResolvedWorkers = runWorkers(runtime.runResolvedWorker(bindings));
252
250
  return NodeDurableHost.of({
253
251
  startupRecovery,
254
252
  admissionOpen: Ref.get(admission),
@@ -257,7 +255,7 @@ const makeHost = Effect.gen(function* () {
257
255
  observe: runtime.observe,
258
256
  abort: runtime.abort,
259
257
  explain: runtime.explain,
260
- explainConversation: runtime.explainConversation,
258
+ explainThread: runtime.explainThread,
261
259
  verify: runtime.verify,
262
260
  retry: runtime.retry,
263
261
  wake: runtime.wake,
@@ -281,15 +279,19 @@ const makeHost = Effect.gen(function* () {
281
279
  * shutdown, provides correctness (DEPLOY-006).
282
280
  */
283
281
  var NodeDurableHost = class NodeDurableHost extends Context.Service()("@effect-agent/platform-node/NodeDurableHost") {
284
- /** Host gates over an already-assembled `NodeDurableRuntime` stack. */
285
- static layer = Layer.effect(NodeDurableHost)(makeHost);
282
+ /**
283
+ * Host gates over an assembled `NodeDurableRuntime` stack. Bindings must carry the exact
284
+ * digests stored by submitters. Omission registers no Agents, so resolved work fails closed.
285
+ */
286
+ static layer = (bindings = []) => Layer.effect(NodeDurableHost)(makeHost(bindings));
286
287
  /** The complete DN host: `NodeDurableRuntime.layer(options)` plus the host lifecycle gates. */
287
288
  static layerStack(options) {
288
- return NodeDurableHost.layer.pipe(Layer.provideMerge(NodeDurableRuntime.layer(options)));
289
+ const { bindings = [], ...runtimeOptions } = options;
290
+ return NodeDurableHost.layer(bindings).pipe(Layer.provideMerge(NodeDurableRuntime.layer(runtimeOptions)));
289
291
  }
290
292
  };
291
293
  //#endregion
292
- //#region src/scheduling.ts
294
+ //#region src/subscriptions.ts
293
295
  const passthroughSubmitAgent = (agentId) => ({ definition: {
294
296
  id: agentId,
295
297
  input: PersistedJson
@@ -299,30 +301,79 @@ const corrupt = (operation) => ScheduleStorageError.make({
299
301
  operation,
300
302
  reason: "corrupt"
301
303
  });
302
- /**
303
- * Scheduled admission through the existing host gate. Once the gate admits the call, every
304
- * runtime failure stays ambiguous because the Submission may already have committed.
305
- */
306
- const nodeScheduledInputAdmissionLayer = Layer.effect(ScheduledInputAdmission, Effect.gen(function* () {
304
+ /** Ordinary prepared admission through the Scope-owned Node host gate. */
305
+ const nodePreparedInputAdmissionLayer = Layer.effect(PreparedInputAdmission, Effect.gen(function* () {
307
306
  const host = yield* NodeDurableHost;
308
- return ScheduledInputAdmission.of({ submit: (envelope) => host.submit(passthroughSubmitAgent(envelope.agentId), envelope.input, {
309
- conversationId: envelope.conversationId,
307
+ return PreparedInputAdmission.of({ submit: (envelope) => host.submit(passthroughSubmitAgent(envelope.agentId), envelope.input, {
308
+ threadId: envelope.threadId,
310
309
  principal: envelope.deliveryPrincipal,
311
310
  idempotencyKey: envelope.admissionKey,
312
311
  definitions: envelope.definitions
313
312
  }).pipe(Effect.catchTags({
314
313
  AdmissionClosed: () => Effect.fail(ScheduledInputRetryable.make({ reason: "host-closed" })),
315
- AgentInputError: () => Effect.fail(corrupt("scheduled admission input")),
316
- AdmissionConflict: () => Effect.fail(corrupt("scheduled admission conflict")),
314
+ AgentInputError: () => Effect.fail(corrupt("prepared admission input")),
315
+ AdmissionConflict: () => Effect.fail(corrupt("prepared admission conflict")),
317
316
  DigestError: () => Effect.fail(ambiguous()),
318
317
  LedgerError: () => Effect.fail(ambiguous()),
319
- ConversationStoreError: () => Effect.fail(ambiguous()),
320
- ConversationNotMaterialized: () => Effect.fail(ambiguous()),
318
+ ThreadStoreError: () => Effect.fail(ambiguous()),
319
+ ThreadNotMaterialized: () => Effect.fail(ambiguous()),
321
320
  AppendConflict: () => Effect.fail(ambiguous()),
322
321
  FenceRejected: () => Effect.fail(ambiguous()),
323
322
  DurableRuntimeFailpointError: () => Effect.fail(ambiguous())
324
323
  })) });
325
324
  }));
325
+ const preparedFromSchedule = (envelope) => ({
326
+ schemaVersion: 1,
327
+ threadId: envelope.threadId,
328
+ deliveryPrincipal: envelope.deliveryPrincipal,
329
+ agentId: envelope.agentId,
330
+ definitions: envelope.definitions,
331
+ input: envelope.input,
332
+ inputDigest: envelope.inputDigest,
333
+ admissionKey: envelope.admissionKey,
334
+ authorization: envelope.authorization
335
+ });
336
+ const nodeScheduledInputAdmissionLayer = Layer.effect(ScheduledInputAdmission, Effect.map(PreparedInputAdmission, (admission) => ScheduledInputAdmission.of({ submit: (envelope) => admission.submit(preparedFromSchedule(envelope)) }))).pipe(Layer.provide(nodePreparedInputAdmissionLayer));
337
+ const reportPassFailure$1 = (cause) => Cause.hasInterruptsOnly(cause) ? Effect.interrupt : Effect.logWarning("Node subscription pass failed").pipe(Effect.annotateLogs({ failureTag: Option.match(Cause.findErrorOption(cause), {
338
+ onNone: () => "Defect",
339
+ onSome: (error) => error._tag
340
+ }) }), Effect.as(false));
341
+ const nodeSubscriptionDriverLayer = (limits) => Layer.effectDiscard(Effect.gen(function* () {
342
+ const driver = yield* SubscriptionDriver;
343
+ const store = yield* SubscriptionStore;
344
+ const run = Effect.gen(function* () {
345
+ while (true) {
346
+ if (!(yield* driver.runDue.pipe(Effect.map((pass) => pass.failed === 0), Effect.catchCause(reportPassFailure$1)))) {
347
+ yield* Effect.sleep(Duration.millis(limits.retryMillis));
348
+ continue;
349
+ }
350
+ const deadline = yield* store.nextDeadline.pipe(Effect.exit);
351
+ if (Exit.isFailure(deadline)) {
352
+ yield* reportPassFailure$1(deadline.cause);
353
+ yield* Effect.sleep(Duration.millis(limits.retryMillis));
354
+ continue;
355
+ }
356
+ const nowMillis = yield* Effect.clockWith((clock) => clock.currentTimeMillis);
357
+ const delay = deadline.value === null ? limits.retryMillis : Math.max(1, Math.min(deadline.value - nowMillis, limits.retryMillis));
358
+ yield* Effect.sleep(Duration.millis(delay));
359
+ }
360
+ });
361
+ yield* Effect.forkScoped(run);
362
+ }));
363
+ /**
364
+ * One Scope-owned subscription partition in the sole process owning its SQLite database.
365
+ * Indexed polling repairs restart and lost wake state; closing the Scope interrupts the driver.
366
+ */
367
+ var NodeSubscriptions = class {
368
+ static layer(options = {}) {
369
+ const limits = options.limits ?? defaultSubscriptionLimits;
370
+ const publicServices = Layer.merge(Subscriptions.layer(limits), SubscriptionIntake.layer(limits));
371
+ const driver = nodeSubscriptionDriverLayer(limits).pipe(Layer.provide(SubscriptionDriver.layer(limits)));
372
+ return Layer.merge(publicServices, driver).pipe(Layer.provide(nodePreparedInputAdmissionLayer), Layer.provide(NodeCrypto.layer));
373
+ }
374
+ };
375
+ //#endregion
376
+ //#region src/scheduling.ts
326
377
  /** One bounded hint slot for the single supported Node scheduler. Indexed polling repairs loss. */
327
378
  const nodeScheduleWakeLayer = Layer.effect(ScheduleWake, Effect.gen(function* () {
328
379
  const hints = yield* PubSub.sliding(1);
@@ -368,6 +419,6 @@ var NodeScheduling = class {
368
419
  }
369
420
  };
370
421
  //#endregion
371
- export { AdmissionClosed, NodeDurableHost, NodeDurableRuntime, NodeDurableRuntimeConfig, NodeDurableRuntimeConfigValue, NodePlatformConfigError, NodeScheduling, NodeWakeSchedulerConfig, nodeScheduleWakeLayer, nodeScheduledInputAdmissionLayer, nodeWakeSchedulerLayer, ownershipDrainLayer };
422
+ export { AdmissionClosed, NodeDurableHost, NodeDurableRuntime, NodeDurableRuntimeConfig, NodeDurableRuntimeConfigValue, NodePlatformConfigError, NodeScheduling, NodeSubscriptions, NodeWakeSchedulerConfig, nodePreparedInputAdmissionLayer, nodeScheduleWakeLayer, nodeScheduledInputAdmissionLayer, nodeWakeSchedulerLayer, ownershipDrainLayer };
372
423
 
373
424
  //# sourceMappingURL=index.mjs.map