@effect-agent/platform-node 0.1.0-beta.55 → 0.1.0-beta.57
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/{NodeDurableAgentRuntime-CPmWN-L_.d.mts → NodeDurableAgentRuntime-CFElFzNF.d.mts} +24 -16
- package/dist/NodeDurableAgentRuntime.d.mts +1 -1
- package/dist/NodeDurableAgentRuntime.mjs +7 -4
- package/dist/NodeDurableAgentRuntime.mjs.map +1 -1
- package/dist/NodeDurableHost-BMSajuQn.mjs +194 -0
- package/dist/NodeDurableHost-BMSajuQn.mjs.map +1 -0
- package/dist/NodeDurableHost.d.mts +22 -16
- package/dist/NodeDurableHost.mjs +2 -111
- package/dist/NodeSubscriptions.d.mts +1 -1
- package/dist/NodeSubscriptions.mjs +4 -41
- package/dist/NodeSubscriptions.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/src/NodeDurableAgentRuntime.ts +25 -6
- package/src/NodeDurableHost.ts +46 -7
- package/src/NodeSubscriptions.ts +4 -67
- package/src/internal/message-delivery.ts +53 -0
- package/src/internal/prepared-admission.ts +81 -0
- package/dist/NodeDurableHost.mjs.map +0 -1
|
@@ -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-
|
|
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
|
-
*
|
|
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
|
|
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<
|
|
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> :
|
|
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> :
|
|
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> :
|
|
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
|
|
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
|
|
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<
|
|
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> :
|
|
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> :
|
|
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> :
|
|
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
|
|
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
|
package/dist/NodeDurableHost.mjs
CHANGED
|
@@ -1,111 +1,2 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
|
|
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/
|
|
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,
|
|
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":";;;;;;;;;;;;;;;;;;;AAgCA,MAAM,0BAA0B,aAAgE,EAC9F,YAAY;CAAE,IAAI;CAAS,OAAO;AAAc,EAClD;AAEA,MAAM,kBACJ,wBAAwB,KAAK,EAAE,QAAQ,YAAY,CAAC;AAEtD,MAAM,WAAW,cACf,qBAAqB,KAAK;CAAE;CAAW,QAAQ;AAAU,CAAC;;AAG5D,MAAa,kCAIT,MAAM,OACR,wBACA,OAAO,IAAI,aAAa;CACtB,MAAM,OAAO,OAAO;CAEpB,OAAO,uBAAuB,GAAG;EAC/B,mBAAmB,YACjB,KACG,iBAAiB,OAAO,CAAC,CACzB,KAAK,OAAO,eAAe,wBAAwB,KAAK,EAAE,QAAQ,UAAU,CAAC,CAAC,CAAC;EACpF,SAAS,aACP,KACG,OAAO,uBAAuB,SAAS,OAAO,GAAG,SAAS,OAAO;GAChE,UAAU,SAAS;GACnB,WAAW,SAAS;GACpB,gBAAgB,SAAS;GACzB,GAAI,SAAS,mBAAmB,KAAA,IAC5B,CAAC,IACD,EAAE,gBAAgB,SAAS,eAAe;GAC9C,GAAI,SAAS,mBAAmB,KAAA,IAC5B,CAAC,IACD,EAAE,gBAAgB,SAAS,eAAe;GAC9C,aAAa,SAAS;EACxB,CAAC,CAAC,CACD,KACC,OAAO,UAAU;GACf,uBACE,OAAO,KAAK,wBAAwB,KAAK,EAAE,QAAQ,cAAc,CAAC,CAAC;GACrE,uBAAuB,OAAO,KAAK,QAAQ,0BAA0B,CAAC;GACtE,yBAAyB,OAAO,KAAK,QAAQ,6BAA6B,CAAC;GAC3E,mBAAmB,OAAO,KAAK,UAAU,CAAC;GAC1C,uBAAuB,UACrB,MAAM,WAAW,YACb,sBAAsB,KAAK,EAAE,MAAM,MAAM,KAAK,CAAC,IAC/C,wBAAwB,KAAK,EAC3B,QAAQ,MAAM,WAAW,aAAa,aAAa,UACrD,CAAC;GACP,mBAAmB,wBAAwB,KAAK,EAAE,QAAQ,UAAU,CAAC;GACrE,wBAAwB,OAAO,KAAK,UAAU,CAAC;GAC/C,6BAA6B,OAAO,KAAK,UAAU,CAAC;GACpD,sBAAsB,OAAO,KAAK,UAAU,CAAC;GAC7C,qBAAqB,OAAO,KAAK,UAAU,CAAC;GAC5C,oCAAoC,OAAO,KAAK,UAAU,CAAC;EAC7D,CAAC,CACH;CACN,CAAC;AACH,CAAC,CACH;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"}
|
|
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-
|
|
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 {
|
|
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.
|
|
1
|
+
{"name":"@effect-agent/platform-node","version":"0.1.0-beta.57","dependencies":{"@effect-agent/core":"0.1.0-beta.57","@effect-agent/engine":"0.1.0-beta.57","@effect-agent/storage-sqlite":"0.1.0-beta.57","@effect-agent/thread":"0.1.0-beta.57","@effect-agent/workflow":"0.1.0-beta.57","@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.57","@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 {
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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,
|
|
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
|
),
|
package/src/NodeDurableHost.ts
CHANGED
|
@@ -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.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
*
|
|
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. */
|