@librechat/agents 3.7.1 → 3.7.3

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.
@@ -0,0 +1,797 @@
1
+ let _langchain_langgraph = require("@langchain/langgraph");
2
+ let node_crypto = require("node:crypto");
3
+ let _langchain_core_singletons = require("@langchain/core/singletons");
4
+ //#region src/eventActor/EventActorExecutor.ts
5
+ const DEFAULT_MAX_DEPTH = 1;
6
+ const DEFAULT_DORMANT_CHECKPOINT_TTL_MS = 1440 * 60 * 1e3;
7
+ function createInvocationCheckpointNs(request, attemptId = (0, node_crypto.randomUUID)()) {
8
+ return `event-actor/${(0, node_crypto.createHash)("sha256").update(request.actorThreadId).update("\0").update(request.invocationId).update("\0").update(attemptId).digest("hex").slice(0, 32)}`;
9
+ }
10
+ function snapshotEvent(event) {
11
+ const ancestors = /* @__PURE__ */ new WeakSet();
12
+ const clone = (value) => {
13
+ if (value === null || typeof value === "string" || typeof value === "boolean") return value;
14
+ if (typeof value === "number") {
15
+ if (!Number.isFinite(value)) throw new Error("Event actor event numbers must be finite");
16
+ return Object.is(value, -0) ? 0 : value;
17
+ }
18
+ if (typeof value !== "object") throw new Error("Event actor events must contain only JSON values");
19
+ if (ancestors.has(value)) throw new Error("Event actor events must not contain cycles");
20
+ ancestors.add(value);
21
+ try {
22
+ if (Array.isArray(value)) {
23
+ if (Object.getOwnPropertySymbols(value).length > 0) throw new Error("Event actor event arrays must not contain symbols");
24
+ const snapshot = [];
25
+ for (let index = 0; index < value.length; index += 1) {
26
+ if (!Object.hasOwn(value, index)) throw new Error("Event actor event arrays must not contain holes");
27
+ snapshot.push(clone(value[index]));
28
+ }
29
+ if (Object.keys(value).length !== value.length) throw new Error("Event actor event arrays must not contain named properties");
30
+ return Object.freeze(snapshot);
31
+ }
32
+ const prototype = Object.getPrototypeOf(value);
33
+ if (prototype !== Object.prototype && prototype !== null) throw new Error("Event actor events must contain only JSON objects");
34
+ if (Object.getOwnPropertySymbols(value).length > 0) throw new Error("Event actor events must not contain symbol keys");
35
+ const snapshot = {};
36
+ for (const key of Object.keys(value).sort()) {
37
+ const item = value[key];
38
+ Object.defineProperty(snapshot, key, {
39
+ configurable: false,
40
+ enumerable: true,
41
+ writable: false,
42
+ value: clone(item)
43
+ });
44
+ }
45
+ return Object.freeze(snapshot);
46
+ } finally {
47
+ ancestors.delete(value);
48
+ }
49
+ };
50
+ return clone(event);
51
+ }
52
+ function snapshotCheckpointReference(checkpoint) {
53
+ return {
54
+ threadId: checkpoint.threadId,
55
+ ...checkpoint.checkpointId == null ? {} : { checkpointId: checkpoint.checkpointId },
56
+ checkpointNs: checkpoint.checkpointNs
57
+ };
58
+ }
59
+ function snapshotCheckpointFork(checkpoint) {
60
+ return {
61
+ ...snapshotCheckpointReference(checkpoint),
62
+ invocationId: checkpoint.invocationId
63
+ };
64
+ }
65
+ function snapshotHead(head) {
66
+ return {
67
+ actorThreadId: head.actorThreadId,
68
+ generation: Object.is(head.generation, -0) ? 0 : head.generation,
69
+ ...head.checkpoint == null ? {} : { checkpoint: snapshotCheckpointReference(head.checkpoint) }
70
+ };
71
+ }
72
+ function snapshotInvocationReference(invocation) {
73
+ return {
74
+ actorThreadId: invocation.actorThreadId,
75
+ invocationId: invocation.invocationId,
76
+ depth: invocation.depth,
77
+ continuation: invocation.continuation,
78
+ base: snapshotHead(invocation.base),
79
+ fork: snapshotCheckpointFork(invocation.fork)
80
+ };
81
+ }
82
+ function snapshotInvocation(invocation) {
83
+ return {
84
+ ...snapshotInvocationReference(invocation),
85
+ event: snapshotEvent(invocation.event)
86
+ };
87
+ }
88
+ function snapshotPrepareRequest(request) {
89
+ return {
90
+ actorThreadId: request.actorThreadId,
91
+ invocationId: request.invocationId,
92
+ depth: request.depth,
93
+ event: snapshotEvent(request.event)
94
+ };
95
+ }
96
+ function freezeInvocationReference(invocation) {
97
+ const snapshot = snapshotInvocationReference(invocation);
98
+ if (snapshot.base.checkpoint != null) Object.freeze(snapshot.base.checkpoint);
99
+ Object.freeze(snapshot.base);
100
+ Object.freeze(snapshot.fork);
101
+ return Object.freeze(snapshot);
102
+ }
103
+ function freezeInvocation(invocation) {
104
+ return Object.freeze({
105
+ ...freezeInvocationReference(invocation),
106
+ event: snapshotEvent(invocation.event)
107
+ });
108
+ }
109
+ function snapshotPreparedInvocation(invocation) {
110
+ return Object.freeze({
111
+ ...freezeInvocation(invocation),
112
+ preparationDigest: invocation.preparationDigest
113
+ });
114
+ }
115
+ function canonicalHead(head) {
116
+ if (head.checkpoint == null) return {
117
+ actorThreadId: head.actorThreadId,
118
+ generation: head.generation,
119
+ checkpoint: null
120
+ };
121
+ return {
122
+ actorThreadId: head.actorThreadId,
123
+ generation: head.generation,
124
+ checkpoint: {
125
+ threadId: head.checkpoint.threadId,
126
+ checkpointId: head.checkpoint.checkpointId ?? null,
127
+ checkpointNs: head.checkpoint.checkpointNs
128
+ }
129
+ };
130
+ }
131
+ function serializeInvocationPreparation(invocation) {
132
+ return JSON.stringify({
133
+ kind: "invocation",
134
+ actorThreadId: invocation.actorThreadId,
135
+ invocationId: invocation.invocationId,
136
+ depth: invocation.depth,
137
+ continuation: invocation.continuation,
138
+ base: canonicalHead(invocation.base),
139
+ fork: {
140
+ invocationId: invocation.fork.invocationId,
141
+ threadId: invocation.fork.threadId,
142
+ checkpointId: invocation.fork.checkpointId ?? null,
143
+ checkpointNs: invocation.fork.checkpointNs
144
+ },
145
+ event: snapshotEvent(invocation.event)
146
+ });
147
+ }
148
+ function serializeUnavailablePreparation(request, head) {
149
+ return JSON.stringify({
150
+ kind: "checkpoint_unavailable",
151
+ request: {
152
+ actorThreadId: request.actorThreadId,
153
+ invocationId: request.invocationId,
154
+ depth: request.depth,
155
+ event: snapshotEvent(request.event)
156
+ },
157
+ head: canonicalHead(head)
158
+ });
159
+ }
160
+ function freezePrepareRequest(request) {
161
+ return Object.freeze(snapshotPrepareRequest(request));
162
+ }
163
+ function freezeHead(head) {
164
+ const snapshot = snapshotHead(head);
165
+ if (snapshot.checkpoint != null) Object.freeze(snapshot.checkpoint);
166
+ return Object.freeze(snapshot);
167
+ }
168
+ function snapshotAmbientConfig(config) {
169
+ if (config == null) return;
170
+ return {
171
+ ...config,
172
+ ...config.tags == null ? {} : { tags: [...config.tags] },
173
+ ...config.metadata == null ? {} : { metadata: { ...config.metadata } },
174
+ ...config.configurable == null ? {} : { configurable: { ...config.configurable } }
175
+ };
176
+ }
177
+ function requireNonEmpty(value, name) {
178
+ if (value.trim() === "") throw new Error(`${name} must not be empty`);
179
+ }
180
+ function validateHead(head, actorThreadId, checkpointRequired = false) {
181
+ if (head.actorThreadId !== actorThreadId || !Number.isSafeInteger(head.generation) || head.generation < 0) throw new Error("Event actor head is invalid");
182
+ if (head.checkpoint == null) {
183
+ if (checkpointRequired) throw new Error("Committed event actor head has no checkpoint");
184
+ if (head.generation > 0) throw new Error("Advanced event actor head has no checkpoint");
185
+ return;
186
+ }
187
+ requireNonEmpty(head.checkpoint.threadId, "head.checkpoint.threadId");
188
+ if (typeof head.checkpoint.checkpointNs !== "string") throw new Error("head.checkpoint.checkpointNs must be a string");
189
+ requireNonEmpty(head.checkpoint.checkpointId ?? "", "head.checkpoint.checkpointId");
190
+ }
191
+ function validateInvocation(request, invocation, continuation, checkpointNs, maxDepth, expectedHead) {
192
+ validateInvocationReference(invocation, maxDepth);
193
+ if (invocation.actorThreadId !== request.actorThreadId || invocation.invocationId !== request.invocationId || invocation.depth !== request.depth || invocation.continuation !== continuation) throw new Error("Event actor preparation returned a mismatched invocation");
194
+ if (invocation.base.actorThreadId !== request.actorThreadId || invocation.fork.invocationId !== request.invocationId || invocation.fork.checkpointNs !== checkpointNs) throw new Error("Event actor preparation returned mismatched checkpoint ownership");
195
+ if (expectedHead != null && (expectedHead.actorThreadId !== request.actorThreadId || invocation.base.generation !== expectedHead.generation || invocation.base.checkpoint?.threadId !== expectedHead.checkpoint?.threadId || invocation.base.checkpoint?.checkpointId !== expectedHead.checkpoint?.checkpointId || invocation.base.checkpoint?.checkpointNs !== expectedHead.checkpoint?.checkpointNs)) throw new Error("Cold continuation did not use the prepared actor head");
196
+ }
197
+ function validateInvocationReference(invocation, maxDepth) {
198
+ requireNonEmpty(invocation.actorThreadId, "actorThreadId");
199
+ requireNonEmpty(invocation.invocationId, "invocationId");
200
+ if (!Number.isSafeInteger(invocation.depth) || invocation.depth < 1) throw new Error("Event actor invocation depth is invalid");
201
+ if (maxDepth != null && invocation.depth > maxDepth) throw new Error(`Event actor depth ${invocation.depth} exceeds maximum ${maxDepth}`);
202
+ const continuation = invocation.continuation;
203
+ if (continuation !== "warm" && continuation !== "cold") throw new Error("Event actor invocation continuation is invalid");
204
+ validateHead(invocation.base, invocation.actorThreadId);
205
+ if (invocation.fork.invocationId !== invocation.invocationId) throw new Error("Event actor invocation has mismatched checkpoint ownership");
206
+ requireNonEmpty(invocation.fork.threadId, "fork.threadId");
207
+ requireNonEmpty(invocation.fork.checkpointNs, "fork.checkpointNs");
208
+ if (invocation.base.checkpoint != null) {
209
+ if (invocation.fork.threadId !== invocation.base.checkpoint.threadId) throw new Error("Event actor fork changed its logical checkpoint thread");
210
+ requireNonEmpty(invocation.fork.checkpointId ?? "", "fork.checkpointId for resumed actor");
211
+ if (invocation.continuation === "warm" && invocation.fork.checkpointId !== invocation.base.checkpoint.checkpointId) throw new Error("Warm event actor fork did not start from the committed checkpoint");
212
+ }
213
+ }
214
+ function checkpointIdsMatch(left, right) {
215
+ return left != null && right != null && left.checkpointId === right.checkpointId;
216
+ }
217
+ function checkpointsMatch(left, right) {
218
+ return checkpointIdsMatch(left, right) && left?.threadId === right?.threadId && left?.checkpointNs === right?.checkpointNs;
219
+ }
220
+ function validateTerminalCheckpoint(invocation, checkpoint) {
221
+ if (checkpoint.invocationId !== invocation.invocationId || checkpoint.threadId !== invocation.fork.threadId || checkpoint.checkpointNs !== invocation.fork.checkpointNs || checkpoint.checkpointId == null || checkpoint.checkpointId.trim() === "" || checkpoint.checkpointId === invocation.fork.checkpointId || checkpointIdsMatch(checkpoint, invocation.base.checkpoint)) throw new Error("Event actor result escaped its invocation checkpoint fork");
222
+ }
223
+ function createRunnableConfig(invocation, signal, ambient) {
224
+ const { signal: _ambientSignal, runId: _ambientRunId, runName: _ambientRunName, callbacks: ambientCallbacks, tags: ambientTags, metadata: ambientMetadata, configurable: ambientConfigurable, ...ambientRuntime } = ambient ?? {};
225
+ const configurable = Object.fromEntries(Object.entries(ambientConfigurable ?? {}).filter(([key]) => !key.startsWith("__pregel_") && !key.startsWith("__librechat_") && key !== "lc_run_breaker_scope"));
226
+ delete configurable.run_id;
227
+ delete configurable.thread_id;
228
+ delete configurable.checkpoint_ns;
229
+ delete configurable.checkpoint_id;
230
+ delete configurable.checkpoint_map;
231
+ delete configurable.event_actor_thread_id;
232
+ delete configurable.event_actor_invocation_id;
233
+ delete configurable.event_actor_generation;
234
+ delete configurable.event_actor_depth;
235
+ delete configurable.event_actor_continuation;
236
+ const metadata = Object.fromEntries(Object.entries(ambientMetadata ?? {}).filter(([key]) => !key.startsWith("langgraph_") && !key.startsWith("__pregel_") && key !== "run_id" && key !== "thread_id" && key !== "checkpoint_ns" && key !== "checkpoint_id" && key !== "checkpoint_map"));
237
+ return {
238
+ ...ambientRuntime,
239
+ signal,
240
+ ...ambientCallbacks == null ? {} : { callbacks: ambientCallbacks },
241
+ ...ambientTags == null ? {} : { tags: ambientTags },
242
+ metadata: {
243
+ ...metadata,
244
+ thread_id: invocation.fork.threadId,
245
+ checkpoint_ns: invocation.fork.checkpointNs,
246
+ eventActorThreadId: invocation.actorThreadId,
247
+ eventActorInvocationId: invocation.invocationId,
248
+ eventActorGeneration: invocation.base.generation,
249
+ eventActorDepth: invocation.depth,
250
+ eventActorContinuation: invocation.continuation
251
+ },
252
+ configurable: {
253
+ ...configurable,
254
+ thread_id: invocation.fork.threadId,
255
+ checkpoint_ns: invocation.fork.checkpointNs,
256
+ ...invocation.fork.checkpointId == null ? {} : { checkpoint_id: invocation.fork.checkpointId },
257
+ event_actor_thread_id: invocation.actorThreadId,
258
+ event_actor_invocation_id: invocation.invocationId,
259
+ event_actor_generation: invocation.base.generation,
260
+ event_actor_depth: invocation.depth,
261
+ event_actor_continuation: invocation.continuation
262
+ }
263
+ };
264
+ }
265
+ function asError(error) {
266
+ try {
267
+ return error instanceof Error ? error : new Error(String(error));
268
+ } catch {
269
+ return /* @__PURE__ */ new Error("Unknown event actor error");
270
+ }
271
+ }
272
+ function createIndeterminateResult(invocation, error, result) {
273
+ return Object.freeze({
274
+ status: "commit_indeterminate",
275
+ ...result === void 0 ? {} : { result },
276
+ checkpoint: Object.freeze({
277
+ invocationId: invocation.fork.invocationId,
278
+ threadId: invocation.fork.threadId,
279
+ checkpointNs: invocation.fork.checkpointNs
280
+ }),
281
+ error: asError(error)
282
+ });
283
+ }
284
+ function createSettlementIndeterminateResult(settlement, error) {
285
+ return Object.freeze({
286
+ status: "commit_indeterminate",
287
+ result: settlement.result,
288
+ checkpoint: Object.freeze(snapshotCheckpointFork(settlement.checkpoint)),
289
+ error: asError(error)
290
+ });
291
+ }
292
+ function snapshotAppliedTerminal(invocation, terminal) {
293
+ let result;
294
+ try {
295
+ result = snapshotEvent(terminal.result);
296
+ const snapshot = {
297
+ status: "snapshot_ready",
298
+ result,
299
+ checkpoint: snapshotCheckpointFork(terminal.checkpoint),
300
+ invocation: freezeInvocationReference(invocation)
301
+ };
302
+ validateTerminalCheckpoint(snapshot.invocation, snapshot.checkpoint);
303
+ return snapshot;
304
+ } catch (error) {
305
+ return createIndeterminateResult(invocation, error, result);
306
+ }
307
+ }
308
+ function isAborted(signal) {
309
+ return signal?.aborted === true;
310
+ }
311
+ var EventActorPreparationCancelledError = class extends Error {
312
+ continuation;
313
+ constructor(continuation, reason) {
314
+ super(`Event actor ${continuation} preparation was cancelled`, { cause: reason });
315
+ this.continuation = continuation;
316
+ this.name = "EventActorPreparationCancelledError";
317
+ }
318
+ };
319
+ function resolveExecutionDepth(requestedDepth, ambientConfig) {
320
+ const ambientDepth = ambientConfig?.configurable?.event_actor_depth;
321
+ if (ambientDepth == null) return requestedDepth ?? 1;
322
+ if (!Number.isSafeInteger(ambientDepth) || Number(ambientDepth) < 1) throw new Error("Ambient event actor depth is invalid");
323
+ const nestedDepth = Number(ambientDepth) + 1;
324
+ if (requestedDepth != null && requestedDepth !== nestedDepth) throw new Error(`Nested event actor depth ${requestedDepth} must advance parent depth ${ambientDepth}`);
325
+ return nestedDepth;
326
+ }
327
+ function validateCommittedHead(invocation, checkpoint, head) {
328
+ validateHead(head, invocation.actorThreadId, true);
329
+ if (head.generation !== invocation.base.generation + 1 || head.checkpoint?.threadId !== checkpoint.threadId || head.checkpoint.checkpointNs !== checkpoint.checkpointNs || head.checkpoint.checkpointId !== checkpoint.checkpointId) throw new Error("Event actor commit returned an invalid logical head");
330
+ }
331
+ var EventActorExecutor = class {
332
+ #adapter;
333
+ #maxDepth;
334
+ #dormantCheckpointTtlMs;
335
+ #preparationSigningKey;
336
+ #issuedSettlements = /* @__PURE__ */ new WeakSet();
337
+ #preparationPhases = /* @__PURE__ */ new Map();
338
+ #nextPhaseExpiry = Number.POSITIVE_INFINITY;
339
+ constructor(adapter, options = {}) {
340
+ this.#adapter = adapter;
341
+ this.#maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
342
+ this.#dormantCheckpointTtlMs = options.dormantCheckpointTtlMs ?? DEFAULT_DORMANT_CHECKPOINT_TTL_MS;
343
+ const signingKey = Buffer.from(options.preparationSigningKey ?? (0, node_crypto.randomBytes)(32));
344
+ if (signingKey.byteLength < 32) throw new Error("preparationSigningKey must contain at least 32 bytes");
345
+ this.#preparationSigningKey = signingKey;
346
+ if (!Number.isSafeInteger(this.#maxDepth) || this.#maxDepth < 1) throw new Error("maxDepth must be a positive safe integer");
347
+ if (!Number.isSafeInteger(this.#dormantCheckpointTtlMs) || this.#dormantCheckpointTtlMs < 1) throw new Error("dormantCheckpointTtlMs must be a positive safe integer");
348
+ }
349
+ #signPreparation(payload) {
350
+ return (0, node_crypto.createHmac)("sha256", this.#preparationSigningKey).update(payload).digest("hex");
351
+ }
352
+ #preparationSignatureMatches(signature, payload) {
353
+ if (!/^[a-f0-9]{64}$/.test(signature)) return false;
354
+ return (0, node_crypto.timingSafeEqual)(Buffer.from(signature, "hex"), Buffer.from(this.#signPreparation(payload), "hex"));
355
+ }
356
+ #createPreparedInvocation(invocation) {
357
+ const trustedInvocation = freezeInvocation(invocation);
358
+ const payload = serializeInvocationPreparation(trustedInvocation);
359
+ return Object.freeze({
360
+ ...trustedInvocation,
361
+ preparationDigest: this.#createTimedPreparationDigest(payload)
362
+ });
363
+ }
364
+ #createTimedPreparationDigest(payload) {
365
+ const expiresAt = Math.min(Number.MAX_SAFE_INTEGER, Date.now() + this.#dormantCheckpointTtlMs);
366
+ return `${expiresAt}.${this.#signPreparation(`${expiresAt}\0${payload}`)}`;
367
+ }
368
+ #validateTimedPreparationDigest(preparationDigest, payload, subject, allowExpired = false) {
369
+ requireNonEmpty(preparationDigest, "preparationDigest");
370
+ const match = /^(\d+)\.([a-f0-9]{64})$/.exec(preparationDigest);
371
+ const expiresAt = Number(match?.[1]);
372
+ if (match == null || !Number.isSafeInteger(expiresAt) || expiresAt < 1 || !this.#preparationSignatureMatches(match[2], `${expiresAt}\0${payload}`)) throw new Error(`Event actor ${subject} binding is invalid`);
373
+ if (!allowExpired && expiresAt <= Date.now()) throw new Error(`Event actor ${subject} binding has expired`);
374
+ return expiresAt;
375
+ }
376
+ #validatePreparedInvocation(invocation, allowExpired = false) {
377
+ return this.#validateTimedPreparationDigest(invocation.preparationDigest, serializeInvocationPreparation(invocation), "prepared invocation", allowExpired);
378
+ }
379
+ #prunePreparationPhases(now = Date.now()) {
380
+ this.#nextPhaseExpiry = Number.POSITIVE_INFINITY;
381
+ for (const [digest, phase] of this.#preparationPhases) if ("expiresAt" in phase && phase.expiresAt <= now) this.#preparationPhases.delete(digest);
382
+ else if ("expiresAt" in phase) this.#nextPhaseExpiry = Math.min(this.#nextPhaseExpiry, phase.expiresAt);
383
+ }
384
+ #getPreparationPhase(preparationDigest) {
385
+ if (Date.now() >= this.#nextPhaseExpiry) this.#prunePreparationPhases();
386
+ return this.#preparationPhases.get(preparationDigest);
387
+ }
388
+ #setTerminalPreparationPhase(preparationDigest, status, authorityExpiresAt) {
389
+ const now = Date.now();
390
+ if (now >= this.#nextPhaseExpiry) this.#prunePreparationPhases(now);
391
+ const phase = {
392
+ status,
393
+ expiresAt: Math.max(authorityExpiresAt, Math.min(Number.MAX_SAFE_INTEGER, now + this.#dormantCheckpointTtlMs))
394
+ };
395
+ this.#preparationPhases.set(preparationDigest, phase);
396
+ this.#nextPhaseExpiry = Math.min(this.#nextPhaseExpiry, phase.expiresAt);
397
+ }
398
+ async prepare(request, signal) {
399
+ const trustedRequest = snapshotPrepareRequest(request);
400
+ resolveExecutionDepth(trustedRequest.depth, _langchain_core_singletons.AsyncLocalStorageProviderSingleton.getRunnableConfig());
401
+ this.#validatePrepareRequest(trustedRequest);
402
+ const checkpointNs = createInvocationCheckpointNs(trustedRequest);
403
+ const adapterRequest = {
404
+ ...snapshotPrepareRequest(trustedRequest),
405
+ checkpointNs
406
+ };
407
+ const controller = new AbortController();
408
+ const abort = () => controller.abort(signal?.reason);
409
+ if (isAborted(signal)) abort();
410
+ else signal?.addEventListener("abort", abort, { once: true });
411
+ if (isAborted(controller.signal)) {
412
+ signal?.removeEventListener("abort", abort);
413
+ throw new EventActorPreparationCancelledError("warm", controller.signal.reason);
414
+ }
415
+ let preparation;
416
+ try {
417
+ preparation = await this.#adapter.prepare({ ...adapterRequest }, { signal: controller.signal });
418
+ } catch (error) {
419
+ if (isAborted(controller.signal) && error === controller.signal.reason) throw new EventActorPreparationCancelledError("warm", error);
420
+ throw error;
421
+ } finally {
422
+ signal?.removeEventListener("abort", abort);
423
+ }
424
+ const preparationStatus = preparation.status;
425
+ if (preparationStatus === "ready") {
426
+ const adapterInvocation = snapshotInvocation(preparation.invocation);
427
+ validateInvocation(trustedRequest, adapterInvocation, "warm", checkpointNs, this.#maxDepth);
428
+ const preparedInvocation = this.#createPreparedInvocation({
429
+ ...adapterInvocation,
430
+ event: snapshotEvent(trustedRequest.event)
431
+ });
432
+ if (isAborted(controller.signal)) {
433
+ await this.#discardInvocationReference(snapshotInvocationReference(preparedInvocation), "cancelled");
434
+ throw new EventActorPreparationCancelledError("warm", controller.signal.reason);
435
+ }
436
+ return Object.freeze({
437
+ status: "ready",
438
+ invocation: preparedInvocation
439
+ });
440
+ } else {
441
+ if (preparationStatus !== "checkpoint_unavailable") throw new Error("Event actor preparation returned an invalid status");
442
+ const preparedHead = freezeHead(preparation.head);
443
+ validateHead(preparedHead, trustedRequest.actorThreadId);
444
+ if (isAborted(controller.signal)) throw new EventActorPreparationCancelledError("warm", controller.signal.reason);
445
+ const preparedRequest = freezePrepareRequest(trustedRequest);
446
+ return Object.freeze({
447
+ status: "checkpoint_unavailable",
448
+ request: preparedRequest,
449
+ head: preparedHead,
450
+ preparationDigest: this.#createTimedPreparationDigest(serializeUnavailablePreparation(preparedRequest, preparedHead))
451
+ });
452
+ }
453
+ }
454
+ async coldContinue(preparation, signal) {
455
+ const request = snapshotPrepareRequest(preparation.request);
456
+ const trustedHead = snapshotHead(preparation.head);
457
+ const preparationDigest = preparation.preparationDigest;
458
+ const authorityExpiresAt = this.#validateTimedPreparationDigest(preparationDigest, serializeUnavailablePreparation(request, trustedHead), "unavailable preparation");
459
+ resolveExecutionDepth(request.depth, _langchain_core_singletons.AsyncLocalStorageProviderSingleton.getRunnableConfig());
460
+ this.#validatePrepareRequest(request);
461
+ validateHead(trustedHead, request.actorThreadId);
462
+ const checkpointNs = createInvocationCheckpointNs(request);
463
+ const adapterRequest = {
464
+ ...snapshotPrepareRequest(request),
465
+ checkpointNs
466
+ };
467
+ const controller = new AbortController();
468
+ const abort = () => controller.abort(signal?.reason);
469
+ if (isAborted(signal)) abort();
470
+ else signal?.addEventListener("abort", abort, { once: true });
471
+ if (isAborted(controller.signal)) {
472
+ signal?.removeEventListener("abort", abort);
473
+ throw new EventActorPreparationCancelledError("cold", controller.signal.reason);
474
+ }
475
+ if (this.#getPreparationPhase(preparationDigest) != null) {
476
+ signal?.removeEventListener("abort", abort);
477
+ throw new Error("Event actor unavailable preparation was already consumed");
478
+ }
479
+ this.#preparationPhases.set(preparationDigest, { status: "invoking" });
480
+ let invocation;
481
+ try {
482
+ invocation = await this.#adapter.coldContinue({ ...adapterRequest }, snapshotHead(trustedHead), { signal: controller.signal });
483
+ } catch (error) {
484
+ this.#setTerminalPreparationPhase(preparationDigest, "discarded", authorityExpiresAt);
485
+ if (isAborted(controller.signal) && error === controller.signal.reason) throw new EventActorPreparationCancelledError("cold", error);
486
+ throw error;
487
+ } finally {
488
+ signal?.removeEventListener("abort", abort);
489
+ }
490
+ this.#setTerminalPreparationPhase(preparationDigest, "retained", authorityExpiresAt);
491
+ const adapterInvocation = snapshotInvocation(invocation);
492
+ validateInvocation(request, adapterInvocation, "cold", checkpointNs, this.#maxDepth, trustedHead);
493
+ const trustedInvocation = {
494
+ ...adapterInvocation,
495
+ event: snapshotEvent(request.event)
496
+ };
497
+ if (isAborted(controller.signal)) {
498
+ await this.#discardInvocationReference(snapshotInvocationReference(trustedInvocation), "cancelled");
499
+ this.#setTerminalPreparationPhase(preparationDigest, "discarded", authorityExpiresAt);
500
+ throw new EventActorPreparationCancelledError("cold", controller.signal.reason);
501
+ }
502
+ const preparedInvocation = this.#createPreparedInvocation(trustedInvocation);
503
+ this.#setTerminalPreparationPhase(preparationDigest, "discarded", authorityExpiresAt);
504
+ return preparedInvocation;
505
+ }
506
+ async invoke(invocation, signal) {
507
+ const trustedInvocation = snapshotPreparedInvocation(invocation);
508
+ const authorityExpiresAt = this.#validatePreparedInvocation(trustedInvocation);
509
+ const preparationDigest = trustedInvocation.preparationDigest;
510
+ if (this.#getPreparationPhase(preparationDigest) != null) throw new Error("Event actor prepared invocation was already consumed");
511
+ this.#preparationPhases.set(preparationDigest, { status: "invoking" });
512
+ const settlementInvocation = snapshotInvocationReference(trustedInvocation);
513
+ let terminal;
514
+ try {
515
+ terminal = await this.#invokeWithConfig(snapshotInvocation(trustedInvocation), signal, _langchain_core_singletons.AsyncLocalStorageProviderSingleton.getRunnableConfig());
516
+ } catch (error) {
517
+ if ((0, _langchain_langgraph.isGraphInterrupt)(error) || (0, _langchain_langgraph.isParentCommand)(error)) {
518
+ this.#setTerminalPreparationPhase(preparationDigest, "retained", authorityExpiresAt);
519
+ throw error;
520
+ }
521
+ this.#setTerminalPreparationPhase(preparationDigest, "discardable", authorityExpiresAt);
522
+ await this.discard(trustedInvocation, isAborted(signal) ? "cancelled" : "failed");
523
+ throw error;
524
+ }
525
+ this.#setTerminalPreparationPhase(preparationDigest, "retained", authorityExpiresAt);
526
+ let status;
527
+ try {
528
+ status = terminal.status;
529
+ } catch (error) {
530
+ return createIndeterminateResult(settlementInvocation, error);
531
+ }
532
+ if (status === "applied") {
533
+ const snapshot = snapshotAppliedTerminal(settlementInvocation, terminal);
534
+ return snapshot.status === "snapshot_ready" ? this.#issueSettlement(snapshot) : snapshot;
535
+ }
536
+ if (status !== "completed_no_action") return createIndeterminateResult(settlementInvocation, /* @__PURE__ */ new Error("Event actor invocation returned an invalid status"));
537
+ let completed;
538
+ try {
539
+ completed = Object.freeze({
540
+ status: "completed_no_action",
541
+ ...terminal.result === void 0 ? {} : { result: snapshotEvent(terminal.result) }
542
+ });
543
+ } catch (error) {
544
+ this.#setTerminalPreparationPhase(preparationDigest, "discardable", authorityExpiresAt);
545
+ await this.discard(trustedInvocation, "completed_no_action");
546
+ throw error;
547
+ }
548
+ this.#setTerminalPreparationPhase(preparationDigest, "discardable", authorityExpiresAt);
549
+ await this.discard(trustedInvocation, "completed_no_action");
550
+ return completed;
551
+ }
552
+ #issueSettlement(snapshot) {
553
+ const settlement = Object.freeze({
554
+ status: "applied",
555
+ result: snapshot.result,
556
+ checkpoint: Object.freeze(snapshotCheckpointFork(snapshot.checkpoint)),
557
+ invocation: freezeInvocationReference(snapshot.invocation)
558
+ });
559
+ this.#issuedSettlements.add(settlement);
560
+ return settlement;
561
+ }
562
+ async #invokeWithConfig(invocation, signal, ambientConfig) {
563
+ resolveExecutionDepth(invocation.depth, ambientConfig);
564
+ validateInvocation({
565
+ actorThreadId: invocation.actorThreadId,
566
+ invocationId: invocation.invocationId,
567
+ depth: invocation.depth,
568
+ event: invocation.event
569
+ }, invocation, invocation.continuation, invocation.fork.checkpointNs, this.#maxDepth);
570
+ const controller = new AbortController();
571
+ const abort = () => controller.abort(signal?.reason);
572
+ if (isAborted(signal)) abort();
573
+ else signal?.addEventListener("abort", abort, { once: true });
574
+ const config = createRunnableConfig(invocation, controller.signal, ambientConfig);
575
+ try {
576
+ if (controller.signal.aborted) throw asError(controller.signal.reason ?? "Event actor cancelled");
577
+ return await _langchain_core_singletons.AsyncLocalStorageProviderSingleton.runWithConfig(config, () => this.#adapter.invoke(invocation, {
578
+ signal: controller.signal,
579
+ config
580
+ }));
581
+ } finally {
582
+ signal?.removeEventListener("abort", abort);
583
+ }
584
+ }
585
+ async commit(settlement) {
586
+ if (!this.#issuedSettlements.has(settlement)) throw new Error("Event actor settlement was not issued by this executor");
587
+ const trustedInvocation = snapshotInvocationReference(settlement.invocation);
588
+ validateInvocationReference(trustedInvocation, this.#maxDepth);
589
+ const trustedCheckpoint = snapshotCheckpointFork(settlement.checkpoint);
590
+ validateTerminalCheckpoint(trustedInvocation, trustedCheckpoint);
591
+ this.#issuedSettlements.delete(settlement);
592
+ try {
593
+ const committed = await this.#adapter.commit({
594
+ invocation: snapshotInvocationReference(trustedInvocation),
595
+ expectedHead: snapshotHead(trustedInvocation.base),
596
+ checkpoint: { ...trustedCheckpoint },
597
+ result: settlement.result,
598
+ retention: {
599
+ committedCheckpoints: 2,
600
+ dormantCheckpointTtlMs: this.#dormantCheckpointTtlMs
601
+ }
602
+ });
603
+ const status = committed.status;
604
+ if (status === "committed") {
605
+ const committedHead = snapshotHead(committed.head);
606
+ validateCommittedHead(trustedInvocation, trustedCheckpoint, committedHead);
607
+ return {
608
+ status: "committed",
609
+ head: committedHead
610
+ };
611
+ }
612
+ if (status !== "stale") throw new Error("Event actor commit returned an invalid status");
613
+ const staleHead = committed.head;
614
+ if (staleHead != null) {
615
+ const committedHead = snapshotHead(staleHead);
616
+ validateHead(committedHead, trustedInvocation.actorThreadId);
617
+ if (committedHead.generation <= trustedInvocation.base.generation) throw new Error("Stale event actor head did not advance past its base");
618
+ if (trustedInvocation.base.checkpoint != null && committedHead.checkpoint?.threadId !== trustedInvocation.base.checkpoint.threadId) throw new Error("Stale event actor head changed its checkpoint thread");
619
+ if (checkpointIdsMatch(committedHead.checkpoint, trustedInvocation.base.checkpoint) || checkpointIdsMatch(committedHead.checkpoint, trustedInvocation.fork) || checkpointsMatch(committedHead.checkpoint, trustedCheckpoint)) throw new Error("Stale event actor head does not identify a competing checkpoint");
620
+ return {
621
+ status: "stale",
622
+ head: committedHead
623
+ };
624
+ }
625
+ return { status: "stale" };
626
+ } catch (error) {
627
+ return createSettlementIndeterminateResult(settlement, error);
628
+ }
629
+ }
630
+ async discard(invocation, reason) {
631
+ const discardReason = reason;
632
+ if (discardReason !== "cancelled" && discardReason !== "completed_no_action" && discardReason !== "failed") throw new Error("Event actor discard reason is invalid");
633
+ const trustedInvocation = snapshotPreparedInvocation(invocation);
634
+ const expiresAt = this.#validatePreparedInvocation(trustedInvocation, true);
635
+ const preparationDigest = trustedInvocation.preparationDigest;
636
+ const previousPhase = this.#getPreparationPhase(preparationDigest);
637
+ if (expiresAt <= Date.now() && previousPhase == null) throw new Error("Event actor prepared invocation binding has expired");
638
+ if (previousPhase != null && previousPhase.status !== "discardable") throw new Error("Event actor prepared invocation is no longer discardable");
639
+ this.#preparationPhases.set(preparationDigest, { status: "discarding" });
640
+ try {
641
+ await this.#discardInvocationReference(trustedInvocation, reason);
642
+ this.#setTerminalPreparationPhase(preparationDigest, "discarded", expiresAt);
643
+ } catch (error) {
644
+ if (previousPhase == null) this.#preparationPhases.delete(preparationDigest);
645
+ else {
646
+ this.#preparationPhases.set(preparationDigest, previousPhase);
647
+ if ("expiresAt" in previousPhase) this.#nextPhaseExpiry = Math.min(this.#nextPhaseExpiry, previousPhase.expiresAt);
648
+ }
649
+ throw error;
650
+ }
651
+ }
652
+ #discardInvocationReference(invocation, reason) {
653
+ const trustedInvocation = snapshotInvocationReference(invocation);
654
+ validateInvocationReference(trustedInvocation, this.#maxDepth);
655
+ return this.#adapter.discard({
656
+ invocation: trustedInvocation,
657
+ reason
658
+ });
659
+ }
660
+ #validatePrepareRequest(request) {
661
+ requireNonEmpty(request.actorThreadId, "actorThreadId");
662
+ requireNonEmpty(request.invocationId, "invocationId");
663
+ if (!Number.isSafeInteger(request.depth) || request.depth < 1 || request.depth > this.#maxDepth) throw new Error(`Event actor depth ${request.depth} exceeds maximum ${this.#maxDepth}`);
664
+ }
665
+ async execute(request) {
666
+ const trustedRequest = {
667
+ actorThreadId: request.actorThreadId,
668
+ invocationId: request.invocationId,
669
+ event: snapshotEvent(request.event),
670
+ ...request.depth == null ? {} : { depth: request.depth },
671
+ ...request.signal == null ? {} : { signal: request.signal }
672
+ };
673
+ const ambientConfig = snapshotAmbientConfig(_langchain_core_singletons.AsyncLocalStorageProviderSingleton.getRunnableConfig());
674
+ const depth = resolveExecutionDepth(trustedRequest.depth, ambientConfig);
675
+ const prepareRequest = {
676
+ actorThreadId: trustedRequest.actorThreadId,
677
+ invocationId: trustedRequest.invocationId,
678
+ depth,
679
+ event: trustedRequest.event
680
+ };
681
+ let preparation;
682
+ try {
683
+ preparation = await this.prepare(prepareRequest, trustedRequest.signal);
684
+ } catch (error) {
685
+ if (error instanceof EventActorPreparationCancelledError) return {
686
+ status: "cancelled",
687
+ continuation: error.continuation
688
+ };
689
+ throw error;
690
+ }
691
+ if (preparation.status === "checkpoint_unavailable" && isAborted(trustedRequest.signal)) return {
692
+ status: "cancelled",
693
+ continuation: "cold"
694
+ };
695
+ let invocation;
696
+ try {
697
+ invocation = preparation.status === "ready" ? preparation.invocation : await this.coldContinue(preparation, trustedRequest.signal);
698
+ } catch (error) {
699
+ if (error instanceof EventActorPreparationCancelledError) return {
700
+ status: "cancelled",
701
+ continuation: "cold"
702
+ };
703
+ throw error;
704
+ }
705
+ const continuation = preparation.status === "ready" ? "warm" : "cold";
706
+ const invocationReference = snapshotInvocationReference(invocation);
707
+ const invocationForAdapter = snapshotInvocation(invocation);
708
+ if (isAborted(trustedRequest.signal)) {
709
+ await this.#discardInvocationReference(invocationReference, "cancelled");
710
+ return {
711
+ status: "cancelled",
712
+ continuation
713
+ };
714
+ }
715
+ let terminal;
716
+ try {
717
+ terminal = await this.#invokeWithConfig(invocationForAdapter, trustedRequest.signal, ambientConfig);
718
+ } catch (error) {
719
+ if ((0, _langchain_langgraph.isGraphInterrupt)(error) || (0, _langchain_langgraph.isParentCommand)(error)) throw error;
720
+ const reason = isAborted(trustedRequest.signal) ? "cancelled" : "failed";
721
+ await this.#discardInvocationReference(invocationReference, reason);
722
+ if (reason === "cancelled") return {
723
+ status: "cancelled",
724
+ continuation
725
+ };
726
+ return {
727
+ status: "failed",
728
+ error: asError(error),
729
+ continuation
730
+ };
731
+ }
732
+ let terminalStatus;
733
+ try {
734
+ terminalStatus = terminal.status;
735
+ } catch (error) {
736
+ return {
737
+ ...createIndeterminateResult(invocationReference, error),
738
+ continuation
739
+ };
740
+ }
741
+ if (terminalStatus === "completed_no_action") {
742
+ let result;
743
+ try {
744
+ result = terminal.result === void 0 ? void 0 : snapshotEvent(terminal.result);
745
+ } catch (error) {
746
+ await this.#discardInvocationReference(invocationReference, "completed_no_action");
747
+ return {
748
+ status: "failed",
749
+ error: asError(error),
750
+ continuation
751
+ };
752
+ }
753
+ await this.#discardInvocationReference(invocationReference, "completed_no_action");
754
+ return {
755
+ status: "completed_no_action",
756
+ ...result === void 0 ? {} : { result },
757
+ continuation
758
+ };
759
+ }
760
+ if (terminalStatus !== "applied") return {
761
+ ...createIndeterminateResult(invocationReference, /* @__PURE__ */ new Error("Event actor invocation returned an invalid status")),
762
+ continuation
763
+ };
764
+ const appliedSnapshot = snapshotAppliedTerminal(invocationReference, terminal);
765
+ if (appliedSnapshot.status === "commit_indeterminate") return {
766
+ ...appliedSnapshot,
767
+ continuation
768
+ };
769
+ const trustedTerminal = this.#issueSettlement(appliedSnapshot);
770
+ const committed = await this.commit(trustedTerminal);
771
+ if (committed.status === "commit_indeterminate") return {
772
+ ...committed,
773
+ continuation
774
+ };
775
+ if (committed.status === "stale") return {
776
+ status: "commit_conflict",
777
+ result: trustedTerminal.result,
778
+ checkpoint: { ...trustedTerminal.checkpoint },
779
+ ...committed.head == null ? {} : { head: snapshotHead(committed.head) },
780
+ continuation
781
+ };
782
+ return {
783
+ status: "applied",
784
+ result: trustedTerminal.result,
785
+ head: committed.head,
786
+ continuation
787
+ };
788
+ }
789
+ };
790
+ function createEventActorExecutor(adapter, options = {}) {
791
+ return new EventActorExecutor(adapter, options);
792
+ }
793
+ //#endregion
794
+ exports.EventActorExecutor = EventActorExecutor;
795
+ exports.createEventActorExecutor = createEventActorExecutor;
796
+
797
+ //# sourceMappingURL=EventActorExecutor.cjs.map