@effect-agent/platform-node 0.1.0-beta.45 → 0.1.0-beta.46
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-Ceye0Exk.d.mts +170 -0
- package/dist/NodeDurableAgentRuntime.d.mts +2 -0
- package/dist/NodeDurableAgentRuntime.mjs +217 -0
- package/dist/NodeDurableAgentRuntime.mjs.map +1 -0
- package/dist/NodeDurableHost.d.mts +120 -0
- package/dist/NodeDurableHost.mjs +90 -0
- package/dist/NodeDurableHost.mjs.map +1 -0
- package/dist/NodeScheduling.d.mts +22 -0
- package/dist/NodeScheduling.mjs +59 -0
- package/dist/NodeScheduling.mjs.map +1 -0
- package/dist/NodeSubscriptions.d.mts +27 -0
- package/dist/NodeSubscriptions.mjs +103 -0
- package/dist/NodeSubscriptions.mjs.map +1 -0
- package/dist/NodeWakeScheduler-DWdHIhWA.d.mts +27 -0
- package/dist/NodeWakeScheduler.d.mts +2 -0
- package/dist/NodeWakeScheduler.mjs +61 -0
- package/dist/NodeWakeScheduler.mjs.map +1 -0
- package/dist/{workflow.d.mts → NodeWorkflow.d.mts} +3 -3
- package/dist/{workflow.mjs → NodeWorkflow.mjs} +32 -6
- package/dist/NodeWorkflow.mjs.map +1 -0
- package/dist/index.d.mts +6 -313
- package/dist/index.mjs +6 -444
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/package.json +1 -1
- package/src/{layers.ts → NodeDurableAgentRuntime.ts} +24 -17
- package/src/{host.ts → NodeDurableHost.ts} +24 -16
- package/src/{scheduling.ts → NodeScheduling.ts} +7 -5
- package/src/{subscriptions.ts → NodeSubscriptions.ts} +17 -13
- package/src/{wake-scheduler.ts → NodeWakeScheduler.ts} +3 -2
- package/src/{workflow.ts → NodeWorkflow.ts} +52 -3
- package/src/index.ts +5 -5
- package/dist/index.mjs.map +0 -1
- package/dist/workflow.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,444 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
//#region src/wake-scheduler.ts
|
|
8
|
-
/**
|
|
9
|
-
* Bounded in-process wake buffer. Wake hints are droppable by contract (the ledger-scan fallback
|
|
10
|
-
* keeps liveness), so a full buffer slides out the oldest hint instead of growing without bound.
|
|
11
|
-
*/
|
|
12
|
-
const WAKE_BUFFER_CAPACITY = 1024;
|
|
13
|
-
/** Cadence authority for the Node wake scheduler's ledger-scan fallback loop. */
|
|
14
|
-
var NodeWakeSchedulerConfig = class NodeWakeSchedulerConfig extends Context.Service()("@effect-agent/platform-node/NodeWakeSchedulerConfig") {
|
|
15
|
-
static layer(options) {
|
|
16
|
-
return Layer.succeed(NodeWakeSchedulerConfig)({ scanInterval: options.scanInterval });
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
const makeWakeScheduler = Effect.gen(function* () {
|
|
20
|
-
const ledger = yield* SubmissionLedger;
|
|
21
|
-
const config = yield* NodeWakeSchedulerConfig;
|
|
22
|
-
const hints = yield* PubSub.sliding(WAKE_BUFFER_CAPACITY);
|
|
23
|
-
const progress = yield* makeWakeSubscriptionHub;
|
|
24
|
-
yield* Effect.addFinalizer(() => PubSub.shutdown(hints));
|
|
25
|
-
/**
|
|
26
|
-
* One fallback scan: every Thread lane with nonterminal work, deduplicated. A scan
|
|
27
|
-
* failure degrades to "no hints this round" — the wake channel has no error contract and the
|
|
28
|
-
* next round retries — but is logged so a persistently failing ledger stays visible.
|
|
29
|
-
*/
|
|
30
|
-
const scanOnce = Stream.runCollect(ledger.scanNonterminal).pipe(Effect.map((snapshots) => {
|
|
31
|
-
const lanes = /* @__PURE__ */ new Set();
|
|
32
|
-
for (const snapshot of snapshots) lanes.add(snapshot.threadId);
|
|
33
|
-
return [...lanes];
|
|
34
|
-
}), Effect.catch((error) => Effect.logWarning("NodeWakeScheduler fallback scan failed", error).pipe(Effect.as([]))));
|
|
35
|
-
/**
|
|
36
|
-
* Deployment §3: correctness must not depend on in-memory notifications, so every `wakes` run
|
|
37
|
-
* merges its PubSub subscription with a Clock-driven ledger-scan loop. Both live entirely in
|
|
38
|
-
* the consuming run's Scope; no fiber outlives its subscriber.
|
|
39
|
-
*/
|
|
40
|
-
const fallbackScans = Stream.fromIterableEffectRepeat(Effect.sleep(config.scanInterval).pipe(Effect.andThen(scanOnce)));
|
|
41
|
-
return WakeScheduler.of({
|
|
42
|
-
notify: (threadId) => progress.notify(threadId).pipe(Effect.andThen(PubSub.publish(hints, threadId)), Effect.asVoid),
|
|
43
|
-
subscribe: progress.subscribe,
|
|
44
|
-
wakes: Stream.merge(Stream.fromPubSub(hints), fallbackScans)
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
/**
|
|
48
|
-
* In-process Node `WakeScheduler`: `notify` publishes to a bounded sliding PubSub for prompt
|
|
49
|
-
* same-process wakeups, and every `wakes` subscription additionally runs a periodic
|
|
50
|
-
* `SubmissionLedger.scanNonterminal` fallback so a dropped, coalesced, or never-sent notification
|
|
51
|
-
* can never strand accepted work (persistence §14). Delivery may duplicate; consumers already
|
|
52
|
-
* treat wakes as pure liveness hints.
|
|
53
|
-
*/
|
|
54
|
-
const nodeWakeSchedulerLayer = Layer.effect(WakeScheduler)(makeWakeScheduler);
|
|
55
|
-
//#endregion
|
|
56
|
-
//#region src/layers.ts
|
|
57
|
-
const PositiveMillis = Schema.Int.check(Schema.isGreaterThan(0));
|
|
58
|
-
const NonNegativeMillis = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
59
|
-
const WorkerConcurrency = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1), Schema.isLessThanOrEqualTo(64));
|
|
60
|
-
/** The supplied Node durable runtime configuration failed schema validation (DEPLOY-003). */
|
|
61
|
-
var NodePlatformConfigError = class extends Schema.TaggedError()("NodePlatformConfigError", {
|
|
62
|
-
message: Schema.String,
|
|
63
|
-
cause: Schema.optionalKey(Schema.Defect())
|
|
64
|
-
}) {};
|
|
65
|
-
/**
|
|
66
|
-
* Validated Node durable runtime configuration (deployment §4: decoded once during Layer
|
|
67
|
-
* construction, exposed as a typed service). Every cadence is in milliseconds and every bound is
|
|
68
|
-
* finite; `workerConcurrency` caps how many worker loops `NodeDurableHost.runWorkers` drives.
|
|
69
|
-
*/
|
|
70
|
-
var NodeDurableAgentRuntimeConfigValue = class extends Schema.Class("@effect-agent/platform-node/NodeDurableAgentRuntimeConfigValue")({
|
|
71
|
-
/** SQLite database file backing BOTH the Thread Log and the Submission Ledger. */
|
|
72
|
-
filename: Schema.NonEmptyString,
|
|
73
|
-
deploymentId: DeploymentId,
|
|
74
|
-
producerId: ProducerId,
|
|
75
|
-
/** Submission ownership lease duration (D5); liveness hint only, epochs stay authoritative. */
|
|
76
|
-
ownershipLeaseDuration: PositiveMillis,
|
|
77
|
-
/** Finite bound on concurrent worker loops per host (rule 10). */
|
|
78
|
-
workerConcurrency: WorkerConcurrency,
|
|
79
|
-
/** Ledger-scan fallback cadence of the Node wake scheduler (deployment §3). */
|
|
80
|
-
wakeScanInterval: PositiveMillis,
|
|
81
|
-
/** `awaitSettlement` ledger re-check cadence when no wake arrives. */
|
|
82
|
-
settlementPollInterval: PositiveMillis,
|
|
83
|
-
/** Worker ownership-lease renewal cadence. */
|
|
84
|
-
leaseRenewalInterval: PositiveMillis,
|
|
85
|
-
/** Active-Run abort-intent poll cadence. */
|
|
86
|
-
abortPollInterval: PositiveMillis,
|
|
87
|
-
/** Bounded SQLITE_BUSY retry window for write-lock acquisition. */
|
|
88
|
-
busyTimeout: NonNegativeMillis,
|
|
89
|
-
/** Canonical observation poll cadence of the SQLite store. */
|
|
90
|
-
observationPollInterval: NonNegativeMillis,
|
|
91
|
-
/** Opt-in full payload/digest-chain audit while opening the store. */
|
|
92
|
-
verifyOnOpen: Schema.Boolean
|
|
93
|
-
}) {};
|
|
94
|
-
/** Explicit configuration authority for the assembled Node durable runtime. */
|
|
95
|
-
var NodeDurableAgentRuntimeConfig = class extends Context.Service()("@effect-agent/platform-node/NodeDurableAgentRuntimeConfig") {};
|
|
96
|
-
const decodeConfigValue = Schema.decodeUnknownEffect(NodeDurableAgentRuntimeConfigValue);
|
|
97
|
-
const configFromOptions = (options) => decodeConfigValue({
|
|
98
|
-
filename: options.filename,
|
|
99
|
-
deploymentId: options.deploymentId,
|
|
100
|
-
producerId: options.producerId,
|
|
101
|
-
ownershipLeaseDuration: options.ownershipLeaseDuration ?? Duration.toMillis(DEFAULT_OWNERSHIP_LEASE_DURATION),
|
|
102
|
-
workerConcurrency: options.workerConcurrency ?? 1,
|
|
103
|
-
wakeScanInterval: options.wakeScanInterval ?? 1e3,
|
|
104
|
-
settlementPollInterval: options.settlementPollInterval ?? 500,
|
|
105
|
-
leaseRenewalInterval: options.leaseRenewalInterval ?? 1e4,
|
|
106
|
-
abortPollInterval: options.abortPollInterval ?? 500,
|
|
107
|
-
busyTimeout: options.busyTimeout ?? 5e3,
|
|
108
|
-
observationPollInterval: options.observationPollInterval ?? 25,
|
|
109
|
-
verifyOnOpen: options.verifyOnOpen ?? false
|
|
110
|
-
}).pipe(Effect.mapError((error) => NodePlatformConfigError.make({
|
|
111
|
-
message: `Invalid Node durable runtime configuration: ${error.message}`,
|
|
112
|
-
cause: error
|
|
113
|
-
})));
|
|
114
|
-
/** SQLite storage configuration derived from the single validated Node configuration. */
|
|
115
|
-
const sqliteStorageConfigLayer = Layer.effect(SqliteStorageConfig)(Effect.gen(function* () {
|
|
116
|
-
const config = yield* NodeDurableAgentRuntimeConfig;
|
|
117
|
-
return SqliteStorageConfigValue.make({
|
|
118
|
-
observationPollInterval: config.observationPollInterval,
|
|
119
|
-
busyTimeout: config.busyTimeout,
|
|
120
|
-
ownershipLeaseDuration: config.ownershipLeaseDuration,
|
|
121
|
-
verifyOnOpen: config.verifyOnOpen
|
|
122
|
-
});
|
|
123
|
-
}));
|
|
124
|
-
/** Thread coordinator configuration derived from the single validated Node configuration. */
|
|
125
|
-
const durableRuntimeConfigLayer = (estimateCostMicrousd) => Layer.effect(DurableRuntimeConfig)(Effect.gen(function* () {
|
|
126
|
-
const config = yield* NodeDurableAgentRuntimeConfig;
|
|
127
|
-
return DurableRuntimeConfig.make({
|
|
128
|
-
deploymentId: config.deploymentId,
|
|
129
|
-
producerId: config.producerId,
|
|
130
|
-
settlementPollInterval: Duration.millis(config.settlementPollInterval),
|
|
131
|
-
leaseRenewalInterval: Duration.millis(config.leaseRenewalInterval),
|
|
132
|
-
abortPollInterval: Duration.millis(config.abortPollInterval),
|
|
133
|
-
...estimateCostMicrousd === void 0 ? {} : { estimateCostMicrousd }
|
|
134
|
-
});
|
|
135
|
-
}));
|
|
136
|
-
/** Wake fallback-scan cadence derived from the single validated Node configuration. */
|
|
137
|
-
const wakeSchedulerConfigLayer = Layer.effect(NodeWakeSchedulerConfig)(Effect.gen(function* () {
|
|
138
|
-
const config = yield* NodeDurableAgentRuntimeConfig;
|
|
139
|
-
return { scanInterval: Duration.millis(config.wakeScanInterval) };
|
|
140
|
-
}));
|
|
141
|
-
const releaseTrackedOwnership = (ledger, registry) => Effect.gen(function* () {
|
|
142
|
-
const tracked = yield* Ref.getAndSet(registry, /* @__PURE__ */ new Map());
|
|
143
|
-
for (const [submissionId, ownershipToken] of tracked) yield* ledger.releaseOwnership(ReleaseOwnershipRequest.make({
|
|
144
|
-
submissionId,
|
|
145
|
-
ownershipToken
|
|
146
|
-
})).pipe(Effect.catchTags({
|
|
147
|
-
OwnershipLost: () => Effect.void,
|
|
148
|
-
LedgerError: (error) => Effect.logWarning("Ownership drain failed; the lease will expire instead", error)
|
|
149
|
-
}));
|
|
150
|
-
});
|
|
151
|
-
/**
|
|
152
|
-
* Shutdown-drain decorator for a `SubmissionLedger` (deployment §6 step 6): every ownership
|
|
153
|
-
* period granted through this Layer is tracked — claims start tracking, renewals follow token
|
|
154
|
-
* rotation, releases and settlement finalizations stop it — and every ownership still held when
|
|
155
|
-
* the Layer's Scope closes is released so another host can claim the lane immediately instead of
|
|
156
|
-
* waiting for lease expiry. The drain is a liveness courtesy only; producer-epoch fencing remains
|
|
157
|
-
* the correctness authority (DUR-006), and a forced kill simply falls back to lease expiry.
|
|
158
|
-
*/
|
|
159
|
-
const ownershipDrainLayer = Layer.effect(SubmissionLedger)(Effect.gen(function* () {
|
|
160
|
-
const ledger = yield* SubmissionLedger;
|
|
161
|
-
const registry = yield* Ref.make(/* @__PURE__ */ new Map());
|
|
162
|
-
const track = (submissionId, ownershipToken) => Ref.update(registry, (tracked) => new Map(tracked).set(submissionId, ownershipToken));
|
|
163
|
-
const untrack = (submissionId) => Ref.update(registry, (tracked) => {
|
|
164
|
-
const next = new Map(tracked);
|
|
165
|
-
next.delete(submissionId);
|
|
166
|
-
return next;
|
|
167
|
-
});
|
|
168
|
-
yield* Effect.addFinalizer(() => releaseTrackedOwnership(ledger, registry));
|
|
169
|
-
return SubmissionLedger.of({
|
|
170
|
-
capabilities: ledger.capabilities,
|
|
171
|
-
admit: ledger.admit,
|
|
172
|
-
markReady: ledger.markReady,
|
|
173
|
-
lookup: ledger.lookup,
|
|
174
|
-
resolveAdmission: ledger.resolveAdmission,
|
|
175
|
-
recordChildSettled: ledger.recordChildSettled,
|
|
176
|
-
reserveChildBudget: ledger.reserveChildBudget,
|
|
177
|
-
attachChildToReservation: ledger.attachChildToReservation,
|
|
178
|
-
beginChildBudgetRelease: ledger.beginChildBudgetRelease,
|
|
179
|
-
releaseChildBudget: ledger.releaseChildBudget,
|
|
180
|
-
claim: (request) => ledger.claim(request).pipe(Effect.tap((claimed) => claimed._tag === "Some" ? track(claimed.value.submissionId, claimed.value.ownershipToken) : Effect.void)),
|
|
181
|
-
renewOwnership: (request) => ledger.renewOwnership(request).pipe(Effect.tap((renewal) => track(request.submissionId, renewal.ownershipToken)), Effect.tapError((error) => error._tag === "OwnershipLost" ? untrack(request.submissionId) : Effect.void)),
|
|
182
|
-
releaseOwnership: (request) => ledger.releaseOwnership(request).pipe(Effect.tap(() => untrack(request.submissionId)), Effect.tapError((error) => error._tag === "OwnershipLost" ? untrack(request.submissionId) : Effect.void)),
|
|
183
|
-
markInputApplied: ledger.markInputApplied,
|
|
184
|
-
reserveSettlement: ledger.reserveSettlement,
|
|
185
|
-
finalizeSettlement: (request) => ledger.finalizeSettlement(request).pipe(Effect.tap(() => untrack(request.submissionId))),
|
|
186
|
-
requestAbort: ledger.requestAbort,
|
|
187
|
-
claimJoining: ledger.claimJoining,
|
|
188
|
-
markJoined: ledger.markJoined,
|
|
189
|
-
revertJoining: ledger.revertJoining,
|
|
190
|
-
suspend: (request) => ledger.suspend(request).pipe(Effect.tap(() => untrack(request.submissionId))),
|
|
191
|
-
recordApprovalDecision: ledger.recordApprovalDecision,
|
|
192
|
-
markUnknown: ledger.markUnknown,
|
|
193
|
-
recordUnknownResolution: ledger.recordUnknownResolution,
|
|
194
|
-
scanNonterminal: ledger.scanNonterminal,
|
|
195
|
-
loadRecoverySnapshot: ledger.loadRecoverySnapshot
|
|
196
|
-
});
|
|
197
|
-
}));
|
|
198
|
-
/**
|
|
199
|
-
* The DN Layer assembly (deployment §12: a Layer-assembly library, not an app entrypoint).
|
|
200
|
-
* `layer(options)` decodes the configuration, opens ONE SQLite database serving both the
|
|
201
|
-
* Thread Log and the Submission Ledger (so claims fence the same producer epochs), wires
|
|
202
|
-
* the Node wake scheduler with its ledger-scan fallback, wraps the ledger with the shutdown
|
|
203
|
-
* ownership drain, defaults the Tool reconciliation policy to the fail-closed
|
|
204
|
-
* `ToolReconciler.uncertain` (override via `options.toolReconciler`), and provides a ready
|
|
205
|
-
* `DurableAgentRuntime` on top. Storage compatibility is
|
|
206
|
-
* verified during construction: an incompatible database file fails the Layer with
|
|
207
|
-
* `SqliteStorageCompatibilityError` before anything is mutated (DEPLOY-008).
|
|
208
|
-
*/
|
|
209
|
-
var NodeDurableAgentRuntime = class NodeDurableAgentRuntime {
|
|
210
|
-
/** Validated configuration Layer; fails typed when the supplied options are out of bounds. */
|
|
211
|
-
static configLayer(options) {
|
|
212
|
-
return Layer.effect(NodeDurableAgentRuntimeConfig)(configFromOptions(options));
|
|
213
|
-
}
|
|
214
|
-
/** The full DN runtime stack over one SQLite file. */
|
|
215
|
-
static layer(options) {
|
|
216
|
-
return NodeDurableAgentRuntime.assemble(DurableAgentRuntime.layerWithServices, options);
|
|
217
|
-
}
|
|
218
|
-
/** Own typed executable registrations for every worker using this Node runtime. */
|
|
219
|
-
static layerRegistered(registrations, options) {
|
|
220
|
-
return NodeDurableAgentRuntime.assemble(DurableAgentRuntime.layerRegistered(registrations), options);
|
|
221
|
-
}
|
|
222
|
-
/** Construct from registrations already resolved within the enclosing application Scope. */
|
|
223
|
-
static layerWithBindings(bindings, options) {
|
|
224
|
-
return NodeDurableAgentRuntime.assemble(DurableAgentRuntime.layerWithBindings(bindings), options);
|
|
225
|
-
}
|
|
226
|
-
static assemble(runtimeLayer, options) {
|
|
227
|
-
return Layer.unwrap(Effect.map(configFromOptions(options), (config) => {
|
|
228
|
-
const nodeConfigLayer = Layer.succeed(NodeDurableAgentRuntimeConfig)(config);
|
|
229
|
-
const infrastructure = Layer.mergeAll(sqliteStorageConfigLayer, storageFailpointLayer({
|
|
230
|
-
filename: config.filename,
|
|
231
|
-
failpoint: options.storageFailpoint
|
|
232
|
-
}), SqliteClient.layer({ filename: config.filename }), NodeCrypto.layer);
|
|
233
|
-
const runtimeFailpointLayer = options.runtimeFailpoint === void 0 ? DurableRuntimeFailpoint.layer : Layer.succeed(DurableRuntimeFailpoint)({ hit: options.runtimeFailpoint });
|
|
234
|
-
const reconcilerLayer = options.toolReconciler ?? ToolReconciler.uncertain;
|
|
235
|
-
const observerLayer = options.toolFailureObserver === void 0 ? Layer.succeed(CurrentToolFailureObserver)(void 0) : toolFailureObserverLayer(options.toolFailureObserver);
|
|
236
|
-
const ports = Layer.mergeAll(threadStoreLayer, scheduleStoreLayer, nodeWakeSchedulerLayer.pipe(Layer.provideMerge(ownershipDrainLayer.pipe(Layer.provide(submissionLedgerLayer)))));
|
|
237
|
-
return runtimeLayer.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))));
|
|
238
|
-
}));
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
//#endregion
|
|
242
|
-
//#region src/host.ts
|
|
243
|
-
/**
|
|
244
|
-
* Admission is not open on this host: it is shutting down (deployment §6 step 1, DEPLOY-005).
|
|
245
|
-
* Accepted work is unaffected — only NEW admissions are refused.
|
|
246
|
-
*/
|
|
247
|
-
var AdmissionClosed = class extends Schema.TaggedError()("AdmissionClosed", { message: Schema.String }) {};
|
|
248
|
-
const makeHost = Effect.gen(function* () {
|
|
249
|
-
const runtime = yield* DurableAgentRuntime;
|
|
250
|
-
const config = yield* NodeDurableAgentRuntimeConfig;
|
|
251
|
-
const startupRecovery = yield* runtime.runRecovery;
|
|
252
|
-
const admission = yield* Ref.make(true);
|
|
253
|
-
yield* Effect.addFinalizer(() => Ref.set(admission, false));
|
|
254
|
-
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." }))));
|
|
255
|
-
const submit = (agent, input, options) => requireAdmission.pipe(Effect.andThen(runtime.submit(agent, input, options)));
|
|
256
|
-
const runWorkers = (worker) => Effect.forEach(Array.from({ length: config.workerConcurrency }, (_, index) => index), () => worker, {
|
|
257
|
-
concurrency: "unbounded",
|
|
258
|
-
discard: true
|
|
259
|
-
});
|
|
260
|
-
const runResolvedWorkers = runWorkers(runtime.runResolvedWorker);
|
|
261
|
-
return NodeDurableHost.of({
|
|
262
|
-
startupRecovery,
|
|
263
|
-
admissionOpen: Ref.get(admission),
|
|
264
|
-
submit,
|
|
265
|
-
awaitSettlement: runtime.awaitSettlement,
|
|
266
|
-
observe: runtime.observe,
|
|
267
|
-
abort: runtime.abort,
|
|
268
|
-
explain: runtime.explain,
|
|
269
|
-
explainThread: runtime.explainThread,
|
|
270
|
-
verify: runtime.verify,
|
|
271
|
-
retry: runtime.retry,
|
|
272
|
-
wake: runtime.wake,
|
|
273
|
-
scanObligations: runtime.scanObligations,
|
|
274
|
-
runWorkers,
|
|
275
|
-
runResolvedWorkers
|
|
276
|
-
});
|
|
277
|
-
});
|
|
278
|
-
/**
|
|
279
|
-
* Operational host lifecycle for the DN runtime (deployment §2/§5/§6).
|
|
280
|
-
*
|
|
281
|
-
* Startup gates run during Layer construction, so the service existing implies readiness:
|
|
282
|
-
* configuration was schema-decoded, the SQLite file passed the exact-version compatibility check,
|
|
283
|
-
* and every nonterminal Submission went through one full recovery pass BEFORE admission opened.
|
|
284
|
-
* `startupRecovery` is the auditable evidence of that reconciliation pass.
|
|
285
|
-
*
|
|
286
|
-
* Shutdown runs in reverse Layer order when the owning Scope closes: `submit` starts refusing
|
|
287
|
-
* with `AdmissionClosed` first, then the runtime Layer's ownership drain releases every claim
|
|
288
|
-
* still held so another host can take over the lanes immediately, then the SQLite resources
|
|
289
|
-
* close. Forced termination at any point stays safe — the durability protocol, not graceful
|
|
290
|
-
* shutdown, provides correctness (DEPLOY-006).
|
|
291
|
-
*/
|
|
292
|
-
var NodeDurableHost = class NodeDurableHost extends Context.Service()("@effect-agent/platform-node/NodeDurableHost") {
|
|
293
|
-
/**
|
|
294
|
-
* Compile typed registrations and acquire the complete host in one Layer Scope.
|
|
295
|
-
* Node supplies Crypto; model, tool, instruction, and schema services remain required.
|
|
296
|
-
* Startup recovery and shutdown gates are unchanged. Workers start only when the caller
|
|
297
|
-
* runs runResolvedWorkers; this constructor never starts a background worker.
|
|
298
|
-
*/
|
|
299
|
-
static layerRegistered(registrations, options) {
|
|
300
|
-
return NodeDurableHost.layer.pipe(Layer.provideMerge(NodeDurableAgentRuntime.layerRegistered(registrations, options)));
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Host gates over an assembled `NodeDurableAgentRuntime` stack. The runtime Layer owns
|
|
304
|
-
* executable registrations; omission registers no Agents, so resolved work fails closed.
|
|
305
|
-
*/
|
|
306
|
-
static layer = Layer.effect(NodeDurableHost)(makeHost);
|
|
307
|
-
/** The complete DN host: `NodeDurableAgentRuntime.layer(options)` plus the host lifecycle gates. */
|
|
308
|
-
static layerStack(options) {
|
|
309
|
-
const { bindings = [], ...runtimeOptions } = options;
|
|
310
|
-
return NodeDurableHost.layer.pipe(Layer.provideMerge(NodeDurableAgentRuntime.layerWithBindings(bindings, runtimeOptions)));
|
|
311
|
-
}
|
|
312
|
-
};
|
|
313
|
-
//#endregion
|
|
314
|
-
//#region src/subscriptions.ts
|
|
315
|
-
const passthroughSubmitAgent = (agentId) => ({ definition: {
|
|
316
|
-
id: agentId,
|
|
317
|
-
input: PersistedJson
|
|
318
|
-
} });
|
|
319
|
-
const ambiguous = () => ScheduledInputRetryable.make({ reason: "ambiguous" });
|
|
320
|
-
const corrupt = (operation) => ScheduleStorageError.make({
|
|
321
|
-
operation,
|
|
322
|
-
reason: "corrupt"
|
|
323
|
-
});
|
|
324
|
-
/** Ordinary prepared admission through the Scope-owned Node host gate. */
|
|
325
|
-
const nodePreparedInputAdmissionLayer = Layer.effect(PreparedInputAdmission, Effect.gen(function* () {
|
|
326
|
-
const host = yield* NodeDurableHost;
|
|
327
|
-
return PreparedInputAdmission.of({ submit: (envelope) => host.submit(passthroughSubmitAgent(envelope.agentId), envelope.input, {
|
|
328
|
-
threadId: envelope.threadId,
|
|
329
|
-
principal: envelope.deliveryPrincipal,
|
|
330
|
-
idempotencyKey: envelope.admissionKey,
|
|
331
|
-
definitions: envelope.definitions
|
|
332
|
-
}).pipe(Effect.catchTags({
|
|
333
|
-
AdmissionClosed: () => Effect.fail(ScheduledInputRetryable.make({ reason: "host-closed" })),
|
|
334
|
-
AgentInputError: () => Effect.fail(corrupt("prepared admission input")),
|
|
335
|
-
AdmissionConflict: () => Effect.fail(corrupt("prepared admission conflict")),
|
|
336
|
-
DigestError: () => Effect.fail(ambiguous()),
|
|
337
|
-
LedgerError: () => Effect.fail(ambiguous()),
|
|
338
|
-
ThreadStoreError: () => Effect.fail(ambiguous()),
|
|
339
|
-
ThreadNotMaterialized: () => Effect.fail(ambiguous()),
|
|
340
|
-
AppendConflict: () => Effect.fail(ambiguous()),
|
|
341
|
-
FenceRejected: () => Effect.fail(ambiguous()),
|
|
342
|
-
DurableRuntimeFailpointError: () => Effect.fail(ambiguous())
|
|
343
|
-
})) });
|
|
344
|
-
}));
|
|
345
|
-
const preparedFromSchedule = (envelope) => ({
|
|
346
|
-
schemaVersion: 1,
|
|
347
|
-
threadId: envelope.threadId,
|
|
348
|
-
deliveryPrincipal: envelope.deliveryPrincipal,
|
|
349
|
-
agentId: envelope.agentId,
|
|
350
|
-
definitions: envelope.definitions,
|
|
351
|
-
input: envelope.input,
|
|
352
|
-
inputDigest: envelope.inputDigest,
|
|
353
|
-
admissionKey: envelope.admissionKey,
|
|
354
|
-
authorization: envelope.authorization
|
|
355
|
-
});
|
|
356
|
-
const nodeScheduledInputAdmissionLayer = Layer.effect(ScheduledInputAdmission, Effect.map(PreparedInputAdmission, (admission) => ScheduledInputAdmission.of({ submit: (envelope) => admission.submit(preparedFromSchedule(envelope)) }))).pipe(Layer.provide(nodePreparedInputAdmissionLayer));
|
|
357
|
-
const reportPassFailure$1 = (cause) => Cause.hasInterruptsOnly(cause) ? Effect.interrupt : Effect.logWarning("Node subscription pass failed").pipe(Effect.annotateLogs({ failureTag: Option.match(Cause.findErrorOption(cause), {
|
|
358
|
-
onNone: () => "Defect",
|
|
359
|
-
onSome: (error) => error._tag
|
|
360
|
-
}) }), Effect.as(false));
|
|
361
|
-
const nodeSubscriptionDriverLayer = (limits) => Layer.effectDiscard(Effect.gen(function* () {
|
|
362
|
-
const driver = yield* SubscriptionDriver;
|
|
363
|
-
const store = yield* SubscriptionStore;
|
|
364
|
-
const run = Effect.gen(function* () {
|
|
365
|
-
while (true) {
|
|
366
|
-
if (!(yield* driver.runDue.pipe(Effect.map((pass) => pass.failed === 0), Effect.catchCause(reportPassFailure$1)))) {
|
|
367
|
-
yield* Effect.sleep(Duration.millis(limits.retryMillis));
|
|
368
|
-
continue;
|
|
369
|
-
}
|
|
370
|
-
const deadline = yield* store.nextDeadline.pipe(Effect.exit);
|
|
371
|
-
if (Exit.isFailure(deadline)) {
|
|
372
|
-
yield* reportPassFailure$1(deadline.cause);
|
|
373
|
-
yield* Effect.sleep(Duration.millis(limits.retryMillis));
|
|
374
|
-
continue;
|
|
375
|
-
}
|
|
376
|
-
const nowMillis = yield* Effect.clockWith((clock) => clock.currentTimeMillis);
|
|
377
|
-
const delay = deadline.value === null ? limits.retryMillis : Math.max(1, Math.min(deadline.value - nowMillis, limits.retryMillis));
|
|
378
|
-
yield* Effect.sleep(Duration.millis(delay));
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
yield* Effect.forkScoped(run);
|
|
382
|
-
}));
|
|
383
|
-
/**
|
|
384
|
-
* One Scope-owned subscription partition in the sole process owning its SQLite database.
|
|
385
|
-
* Indexed polling repairs restart and lost wake state; closing the Scope interrupts the driver.
|
|
386
|
-
*/
|
|
387
|
-
var NodeSubscriptions = class {
|
|
388
|
-
static layer(options = {}) {
|
|
389
|
-
const limits = options.limits ?? defaultSubscriptionLimits;
|
|
390
|
-
const publicServices = Layer.merge(Subscriptions.layer(limits), SubscriptionIntake.layer(limits));
|
|
391
|
-
const driver = nodeSubscriptionDriverLayer(limits).pipe(Layer.provide(SubscriptionDriver.layer(limits)));
|
|
392
|
-
return Layer.merge(publicServices, driver).pipe(Layer.provide(nodePreparedInputAdmissionLayer), Layer.provide(NodeCrypto.layer));
|
|
393
|
-
}
|
|
394
|
-
};
|
|
395
|
-
//#endregion
|
|
396
|
-
//#region src/scheduling.ts
|
|
397
|
-
/** One bounded hint slot for the single supported Node scheduler. Indexed polling repairs loss. */
|
|
398
|
-
const nodeScheduleWakeLayer = Layer.effect(ScheduleWake, Effect.gen(function* () {
|
|
399
|
-
const hints = yield* PubSub.sliding(1);
|
|
400
|
-
const subscription = yield* PubSub.subscribe(hints);
|
|
401
|
-
yield* Effect.addFinalizer(() => PubSub.shutdown(hints));
|
|
402
|
-
return ScheduleWake.of({
|
|
403
|
-
notify: PubSub.publish(hints, void 0).pipe(Effect.asVoid),
|
|
404
|
-
await: PubSub.take(subscription)
|
|
405
|
-
});
|
|
406
|
-
}));
|
|
407
|
-
const reportPassFailure = (cause) => Cause.hasInterruptsOnly(cause) ? Effect.interrupt : Effect.logWarning("Node scheduling pass failed").pipe(Effect.annotateLogs({ failureTag: Option.match(Cause.findErrorOption(cause), {
|
|
408
|
-
onNone: () => "Defect",
|
|
409
|
-
onSome: (error) => error._tag
|
|
410
|
-
}) }), Effect.as(false));
|
|
411
|
-
const nodeSchedulingDriverLayer = (limits) => Layer.effectDiscard(Effect.gen(function* () {
|
|
412
|
-
const scheduling = yield* ScheduleDriver;
|
|
413
|
-
const store = yield* ScheduleStore;
|
|
414
|
-
const wake = yield* ScheduleWake;
|
|
415
|
-
const run = Effect.gen(function* () {
|
|
416
|
-
while (true) {
|
|
417
|
-
const passSucceeded = yield* scheduling.runDue().pipe(Effect.map((pass) => pass.failed === 0), Effect.catchCause(reportPassFailure));
|
|
418
|
-
const deadlineResult = passSucceeded ? yield* store.nextDeadline().pipe(Effect.result) : Result.fail(ScheduleStorageError.make({
|
|
419
|
-
operation: "driver pass",
|
|
420
|
-
reason: "unavailable"
|
|
421
|
-
}));
|
|
422
|
-
if (Result.isFailure(deadlineResult) && passSucceeded) yield* Effect.logWarning("Node scheduling deadline query failed");
|
|
423
|
-
const nowMillis = yield* Effect.clockWith((clock) => clock.currentTimeMillis);
|
|
424
|
-
const deadlineDelay = Result.isSuccess(deadlineResult) && deadlineResult.success !== null ? Math.max(0, deadlineResult.success - nowMillis) : limits.recoveryPollMillis;
|
|
425
|
-
const delay = Math.min(deadlineDelay, limits.recoveryPollMillis);
|
|
426
|
-
yield* Effect.raceFirst(wake.await, Effect.sleep(Duration.millis(delay)));
|
|
427
|
-
}
|
|
428
|
-
});
|
|
429
|
-
yield* Effect.forkScoped(run);
|
|
430
|
-
}));
|
|
431
|
-
/**
|
|
432
|
-
* Optional Scope-owned Node scheduling service and driver. The caller must provide the existing
|
|
433
|
-
* host, its SQLite ScheduleStore, and an explicit ScheduleAuthorizer.
|
|
434
|
-
*/
|
|
435
|
-
var NodeScheduling = class {
|
|
436
|
-
static layer(options = {}) {
|
|
437
|
-
const limits = options.limits ?? defaultSchedulingLimits;
|
|
438
|
-
return nodeSchedulingDriverLayer(limits).pipe(Layer.provide(ScheduleDriver.layer(limits)), Layer.merge(Scheduling.layer(limits))).pipe(Layer.provide(Layer.mergeAll(nodeScheduledInputAdmissionLayer, nodeScheduleWakeLayer, NodeCrypto.layer)));
|
|
439
|
-
}
|
|
440
|
-
};
|
|
441
|
-
//#endregion
|
|
442
|
-
export { AdmissionClosed, NodeDurableAgentRuntime, NodeDurableAgentRuntimeConfig, NodeDurableAgentRuntimeConfigValue, NodeDurableHost, NodePlatformConfigError, NodeScheduling, NodeSubscriptions, NodeWakeSchedulerConfig, nodePreparedInputAdmissionLayer, nodeScheduleWakeLayer, nodeScheduledInputAdmissionLayer, nodeWakeSchedulerLayer, ownershipDrainLayer };
|
|
443
|
-
|
|
444
|
-
//# sourceMappingURL=index.mjs.map
|
|
1
|
+
import { t as NodeWakeScheduler_exports } from "./NodeWakeScheduler.mjs";
|
|
2
|
+
import { t as NodeDurableAgentRuntime_exports } from "./NodeDurableAgentRuntime.mjs";
|
|
3
|
+
import { t as NodeDurableHost_exports } from "./NodeDurableHost.mjs";
|
|
4
|
+
import { t as NodeSubscriptions_exports } from "./NodeSubscriptions.mjs";
|
|
5
|
+
import { t as NodeScheduling_exports } from "./NodeScheduling.mjs";
|
|
6
|
+
export { NodeDurableAgentRuntime_exports as NodeDurableAgentRuntime, NodeDurableHost_exports as NodeDurableHost, NodeScheduling_exports as NodeScheduling, NodeSubscriptions_exports as NodeSubscriptions, NodeWakeScheduler_exports as NodeWakeScheduler };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
+
return target;
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { __exportAll as t };
|
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.46","dependencies":{"@effect-agent/core":"0.1.0-beta.46","@effect-agent/engine":"0.1.0-beta.46","@effect-agent/storage-sqlite":"0.1.0-beta.46","@effect-agent/thread":"0.1.0-beta.46","@effect-agent/workflow":"0.1.0-beta.46","@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.46","@effect/vitest":"4.0.0-rc.112","effect":"4.0.0-rc.112","typescript":"7.0.2","vite-plus":"0.3.0"},"peerDependencies":{"effect":"^4.0.0-rc.112"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./NodeDurableAgentRuntime":{"types":"./dist/NodeDurableAgentRuntime.d.mts","default":"./dist/NodeDurableAgentRuntime.mjs"},"./NodeDurableHost":{"types":"./dist/NodeDurableHost.d.mts","default":"./dist/NodeDurableHost.mjs"},"./NodeScheduling":{"types":"./dist/NodeScheduling.d.mts","default":"./dist/NodeScheduling.mjs"},"./NodeSubscriptions":{"types":"./dist/NodeSubscriptions.d.mts","default":"./dist/NodeSubscriptions.mjs"},"./NodeWakeScheduler":{"types":"./dist/NodeWakeScheduler.d.mts","default":"./dist/NodeWakeScheduler.mjs"},"./NodeWorkflow":{"types":"./dist/NodeWorkflow.d.mts","default":"./dist/NodeWorkflow.mjs"}},"description":"Class DN layer assembly for Effect Agent: the durable Node/SQLite runtime host, wake scheduler, and ownership drain.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/danieljvdm/effect-agent.git","directory":"packages/platform-node"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type SubmissionId } from "@effect-agent/core/Identifiers";
|
|
2
2
|
import {
|
|
3
3
|
CurrentToolFailureObserver,
|
|
4
4
|
RunContextPreparationPassthrough,
|
|
@@ -7,40 +7,47 @@ import {
|
|
|
7
7
|
type RunContextPreparation,
|
|
8
8
|
type RunCostEstimator,
|
|
9
9
|
type RunToolFailureObserver,
|
|
10
|
-
} from "@effect-agent/engine";
|
|
10
|
+
} from "@effect-agent/engine/RunOptions";
|
|
11
|
+
import { scheduleStoreLayer } from "@effect-agent/storage-sqlite/SqliteScheduleStore";
|
|
11
12
|
import {
|
|
12
|
-
threadStoreLayer,
|
|
13
|
-
scheduleStoreLayer,
|
|
14
13
|
SqliteStorageConfig,
|
|
15
14
|
SqliteStorageConfigValue,
|
|
15
|
+
} from "@effect-agent/storage-sqlite/SqliteStorageConfig";
|
|
16
|
+
import { type SqliteStorageFailpointHandler } from "@effect-agent/storage-sqlite/SqliteStorageFailpoint";
|
|
17
|
+
import { submissionLedgerLayer } from "@effect-agent/storage-sqlite/SqliteSubmissionLedger";
|
|
18
|
+
import {
|
|
19
|
+
threadStoreLayer,
|
|
16
20
|
storageFailpointLayer,
|
|
17
|
-
submissionLedgerLayer,
|
|
18
|
-
type SqliteStorageFailpointHandler,
|
|
19
21
|
type SqliteStorageInitializationError,
|
|
20
|
-
} from "@effect-agent/storage-sqlite";
|
|
22
|
+
} from "@effect-agent/storage-sqlite/SqliteThreadStore";
|
|
21
23
|
import {
|
|
22
24
|
type AgentRegistration,
|
|
23
25
|
type ResolvedBinding,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
type WakeScheduler,
|
|
27
|
-
DEFAULT_OWNERSHIP_LEASE_DURATION,
|
|
28
|
-
DeploymentId,
|
|
26
|
+
} from "@effect-agent/thread/AgentRegistration";
|
|
27
|
+
import {
|
|
29
28
|
DurableAgentRuntime,
|
|
30
29
|
DurableRuntimeConfig,
|
|
30
|
+
} from "@effect-agent/thread/DurableAgentRuntime";
|
|
31
|
+
import {
|
|
31
32
|
DurableRuntimeFailpoint,
|
|
32
|
-
|
|
33
|
+
type DurableRuntimeFailpointHandler,
|
|
34
|
+
} from "@effect-agent/thread/DurableFailpoint";
|
|
35
|
+
import { DeploymentId, ProducerId } from "@effect-agent/thread/Records";
|
|
36
|
+
import { type ScheduleStore } from "@effect-agent/thread/Schedule";
|
|
37
|
+
import {
|
|
38
|
+
DEFAULT_OWNERSHIP_LEASE_DURATION,
|
|
33
39
|
ReleaseOwnershipRequest,
|
|
34
40
|
SubmissionLedger,
|
|
35
|
-
ToolReconciler,
|
|
36
|
-
type DurableRuntimeFailpointHandler,
|
|
37
41
|
type OwnershipToken,
|
|
38
|
-
} from "@effect-agent/thread";
|
|
42
|
+
} from "@effect-agent/thread/SubmissionLedger";
|
|
43
|
+
import { type ThreadStore } from "@effect-agent/thread/ThreadStore";
|
|
44
|
+
import { ToolReconciler } from "@effect-agent/thread/ToolReconciler";
|
|
45
|
+
import { type WakeScheduler } from "@effect-agent/thread/WakeScheduler";
|
|
39
46
|
import { NodeCrypto } from "@effect/platform-node";
|
|
40
47
|
import { SqliteClient } from "@effect/sql-sqlite-node";
|
|
41
48
|
import { Context, type Crypto, Duration, Effect, Layer, Ref, Schema } from "effect";
|
|
42
49
|
|
|
43
|
-
import { NodeWakeSchedulerConfig, nodeWakeSchedulerLayer } from "./
|
|
50
|
+
import { NodeWakeSchedulerConfig, nodeWakeSchedulerLayer } from "./NodeWakeScheduler.ts";
|
|
44
51
|
|
|
45
52
|
const PositiveMillis = Schema.Int.check(Schema.isGreaterThan(0));
|
|
46
53
|
const NonNegativeMillis = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ThreadId, type SubmissionId } from "@effect-agent/core/Identifiers";
|
|
2
|
+
import {
|
|
3
|
+
type IntegrityReport,
|
|
4
|
+
type ObligationReport,
|
|
5
|
+
type ObligationThresholds,
|
|
6
|
+
type RecoveryExplanation,
|
|
7
|
+
type RetryCommand,
|
|
8
|
+
} from "@effect-agent/thread/Admin";
|
|
2
9
|
import {
|
|
3
10
|
type AgentRegistration,
|
|
11
|
+
type ResolvedBinding,
|
|
12
|
+
type DurableBindingFailure,
|
|
13
|
+
} from "@effect-agent/thread/AgentRegistration";
|
|
14
|
+
import {
|
|
4
15
|
DurableAgentRuntime,
|
|
5
|
-
type AbortCommand,
|
|
6
|
-
type AbortIntent,
|
|
7
|
-
type CanonicalRecordEnvelope,
|
|
8
|
-
type ThreadNotMaterialized,
|
|
9
|
-
type ThreadStoreError,
|
|
10
16
|
type DurableAbortFailure,
|
|
11
17
|
type DurableAwaitFailure,
|
|
12
|
-
type ResolvedBinding,
|
|
13
|
-
type DurableBindingFailure,
|
|
14
18
|
type DurableExplainFailure,
|
|
15
19
|
type DurableObserveOptions,
|
|
16
20
|
type DurableObligationFailure,
|
|
@@ -20,16 +24,20 @@ import {
|
|
|
20
24
|
type DurableSubmitOptions,
|
|
21
25
|
type DurableVerifyFailure,
|
|
22
26
|
type DurableWorkerFailure,
|
|
23
|
-
type IntegrityReport,
|
|
24
|
-
type ObligationReport,
|
|
25
|
-
type ObligationThresholds,
|
|
26
|
-
type OperationDenied,
|
|
27
27
|
type Receipt,
|
|
28
|
-
type RecoveryExplanation,
|
|
29
28
|
type RecoveryReport,
|
|
30
|
-
|
|
29
|
+
} from "@effect-agent/thread/DurableAgentRuntime";
|
|
30
|
+
import { type OperationDenied } from "@effect-agent/thread/OperationAuthorizer";
|
|
31
|
+
import { type CanonicalRecordEnvelope } from "@effect-agent/thread/Records";
|
|
32
|
+
import {
|
|
33
|
+
type AbortCommand,
|
|
34
|
+
type AbortIntent,
|
|
31
35
|
type Settlement,
|
|
32
|
-
} from "@effect-agent/thread";
|
|
36
|
+
} from "@effect-agent/thread/SubmissionLedger";
|
|
37
|
+
import {
|
|
38
|
+
type ThreadNotMaterialized,
|
|
39
|
+
type ThreadStoreError,
|
|
40
|
+
} from "@effect-agent/thread/ThreadStore";
|
|
33
41
|
import { type Stream, Context, type Crypto, Effect, Layer, Ref, Schema } from "effect";
|
|
34
42
|
|
|
35
43
|
import {
|
|
@@ -38,7 +46,7 @@ import {
|
|
|
38
46
|
type NodeDurableAgentRuntimeInitializationError,
|
|
39
47
|
type NodeDurableAgentRuntimeOptions,
|
|
40
48
|
type NodeDurableAgentRuntimeServices,
|
|
41
|
-
} from "./
|
|
49
|
+
} from "./NodeDurableAgentRuntime.ts";
|
|
42
50
|
|
|
43
51
|
/**
|
|
44
52
|
* Admission is not open on this host: it is shutting down (deployment §6 step 1, DEPLOY-005).
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type ScheduleProcessFailure,
|
|
3
2
|
type ScheduleAuthorizer,
|
|
4
3
|
type SchedulingLimits,
|
|
5
4
|
ScheduleStorageError,
|
|
6
5
|
ScheduleStore,
|
|
7
6
|
type ScheduleValidationError,
|
|
8
7
|
ScheduleWake,
|
|
8
|
+
defaultSchedulingLimits,
|
|
9
|
+
} from "@effect-agent/thread/Schedule";
|
|
10
|
+
import {
|
|
11
|
+
type ScheduleProcessFailure,
|
|
9
12
|
Scheduling,
|
|
10
13
|
ScheduleDriver,
|
|
11
|
-
|
|
12
|
-
} from "@effect-agent/thread";
|
|
14
|
+
} from "@effect-agent/thread/Scheduling";
|
|
13
15
|
import { NodeCrypto } from "@effect/platform-node";
|
|
14
16
|
import { Cause, Duration, Effect, Layer, Option, PubSub, Result } from "effect";
|
|
15
17
|
|
|
16
|
-
import type { NodeDurableHost } from "./
|
|
17
|
-
import { nodeScheduledInputAdmissionLayer } from "./
|
|
18
|
+
import type { NodeDurableHost } from "./NodeDurableHost.ts";
|
|
19
|
+
import { nodeScheduledInputAdmissionLayer } from "./NodeSubscriptions.ts";
|
|
18
20
|
|
|
19
21
|
/** One bounded hint slot for the single supported Node scheduler. Indexed polling repairs loss. */
|
|
20
22
|
export const nodeScheduleWakeLayer: Layer.Layer<ScheduleWake> = Layer.effect(
|