@librechat/agents 3.7.5 → 3.7.7

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.
@@ -62,12 +62,129 @@ export type EventActorTerminalResult<TResult extends EventActorEvent> = {
62
62
  status: 'completed_no_action';
63
63
  result?: TResult;
64
64
  };
65
+ /** JSON-safe interrupt descriptor retained with a suspended invocation fork. */
66
+ export interface EventActorInterrupt<TPayload extends EventActorEvent = EventActorEvent> {
67
+ id: string;
68
+ payload: TPayload;
69
+ }
70
+ /**
71
+ * Nonterminal adapter outcome. The checkpoint must already contain the pause;
72
+ * the SDK publishes its authority through `suspend` before exposing it.
73
+ */
74
+ export interface EventActorAdapterSuspendedResult<TPayload extends EventActorEvent = EventActorEvent> {
75
+ status: 'suspended';
76
+ checkpoint: EventActorCheckpointFork;
77
+ interrupt: EventActorInterrupt<TPayload>;
78
+ }
79
+ export type EventActorAdapterInvocationResult<TResult extends EventActorEvent, TPayload extends EventActorEvent = EventActorEvent> = EventActorTerminalResult<TResult> | EventActorAdapterSuspendedResult<TPayload>;
80
+ /**
81
+ * Authenticated, versioned, JSON-safe evidence for one nonterminal invocation.
82
+ * Integrity does not make this evidence one-shot; the host's durable current
83
+ * suspension record is the replay and ownership fence. Hosts must capability-
84
+ * route each exact version during rolling deploys and drain or migrate current
85
+ * evidence before rotating away from its signing key.
86
+ */
87
+ export interface EventActorSuspension<TPayload extends EventActorEvent = EventActorEvent> {
88
+ version: 1;
89
+ suspensionId: string;
90
+ attempt: number;
91
+ issuedAt: number;
92
+ expiresAt: number;
93
+ invocation: EventActorInvocationReference;
94
+ checkpoint: EventActorCheckpointFork;
95
+ interrupt: EventActorInterrupt<TPayload>;
96
+ suspensionDigest: string;
97
+ }
98
+ export interface EventActorSuspendedResult<TPayload extends EventActorEvent = EventActorEvent> {
99
+ status: 'suspended';
100
+ suspension: EventActorSuspension<TPayload>;
101
+ }
102
+ export interface EventActorSuspendRequest {
103
+ suspension: EventActorSuspension;
104
+ /** CAS predecessor required when a claimed resume pauses again. */
105
+ previous?: {
106
+ suspensionId: string;
107
+ attempt: number;
108
+ resumeAttemptId: string;
109
+ };
110
+ }
111
+ export type EventActorSuspendResult = {
112
+ status: 'stored';
113
+ } | {
114
+ status: 'stale';
115
+ };
116
+ export interface EventActorAdapterResumeRequest {
117
+ suspension: EventActorSuspension;
118
+ resumeAttemptId: string;
119
+ value: EventActorEvent;
120
+ }
121
+ export type EventActorAdapterResumeResult<TResult extends EventActorEvent> = {
122
+ status: 'claimed';
123
+ result: EventActorAdapterInvocationResult<TResult>;
124
+ } | {
125
+ /** The host proved no action before returning this claimed failure. */
126
+ status: 'claimed_failed';
127
+ error: Error;
128
+ } | {
129
+ status: 'stale';
130
+ };
131
+ export interface EventActorResumeRequest {
132
+ suspension: EventActorSuspension;
133
+ resumeAttemptId: string;
134
+ value: EventActorEvent;
135
+ signal?: AbortSignal;
136
+ }
137
+ export interface EventActorCancelSuspensionRequest {
138
+ suspension: EventActorSuspension;
139
+ cancelAttemptId: string;
140
+ reason?: 'cancelled' | 'expired';
141
+ signal?: AbortSignal;
142
+ }
143
+ export interface EventActorAdapterCancelSuspensionRequest {
144
+ suspension: EventActorSuspension;
145
+ cancelAttemptId: string;
146
+ reason: 'cancelled' | 'expired';
147
+ }
148
+ export type EventActorCancelSuspensionResult = {
149
+ status: 'cancelled';
150
+ } | EventActorIndeterminateResult<EventActorEvent>;
151
+ export type EventActorAdapterCancelSuspensionResult = {
152
+ status: 'cancelled';
153
+ } | {
154
+ status: 'stale';
155
+ };
156
+ export interface EventActorSettleSuspensionRequest {
157
+ suspensionId: string;
158
+ attempt: number;
159
+ resumeAttemptId: string;
160
+ status: 'completed_no_action' | 'failed';
161
+ }
162
+ export type EventActorSettleSuspensionResult = {
163
+ status: 'settled';
164
+ } | {
165
+ status: 'stale';
166
+ };
65
167
  export type EventActorAppliedResult<TResult extends EventActorEvent> = Extract<EventActorTerminalResult<TResult>, {
66
168
  status: 'applied';
67
169
  }> & {
68
- /** Executor-issued one-shot settlement for the invocation that produced this action. */
170
+ /** Executor-issued settlement for the invocation that produced this action. */
69
171
  invocation: EventActorInvocationReference;
172
+ /** Authenticated cross-executor authority for a resumed terminal action. */
173
+ settlementAuthority?: EventActorSettlementAuthority;
70
174
  };
175
+ /**
176
+ * Authenticated fence that binds a resumed terminal result to its claimed
177
+ * suspension. The host must consume it atomically with the actor-head CAS.
178
+ */
179
+ export interface EventActorSettlementAuthority {
180
+ version: 1;
181
+ suspensionId: string;
182
+ attempt: number;
183
+ resumeAttemptId: string;
184
+ issuedAt: number;
185
+ expiresAt: number;
186
+ settlementDigest: string;
187
+ }
71
188
  export interface EventActorIndeterminateResult<TResult extends EventActorEvent> {
72
189
  /** Applied handling cannot be proven safe to retry; retain its fork. */
73
190
  status: 'commit_indeterminate';
@@ -75,7 +192,7 @@ export interface EventActorIndeterminateResult<TResult extends EventActorEvent>
75
192
  checkpoint: EventActorCheckpointFork;
76
193
  error: Error;
77
194
  }
78
- export type EventActorInvocationResult<TResult extends EventActorEvent> = EventActorAppliedResult<TResult> | EventActorIndeterminateResult<TResult> | Extract<EventActorTerminalResult<TResult>, {
195
+ export type EventActorInvocationResult<TResult extends EventActorEvent> = EventActorAppliedResult<TResult> | EventActorIndeterminateResult<TResult> | EventActorSuspendedResult | Extract<EventActorTerminalResult<TResult>, {
79
196
  status: 'completed_no_action';
80
197
  }>;
81
198
  export interface EventActorInvocationContext {
@@ -101,6 +218,8 @@ export interface EventActorCommitRequest<TResult extends EventActorEvent> {
101
218
  expectedHead: EventActorHead;
102
219
  checkpoint: EventActorCheckpointFork;
103
220
  result: TResult;
221
+ /** Host must consume this suspension fence atomically with the head CAS. */
222
+ settlementAuthority?: EventActorSettlementAuthority;
104
223
  retention: {
105
224
  committedCheckpoints: 2;
106
225
  dormantCheckpointTtlMs: number;
@@ -123,7 +242,11 @@ export interface EventActorDiscardRequest {
123
242
  /**
124
243
  * Host adapter for durable actor state and the concrete agent invocation.
125
244
  * `commit` must compare both the expected generation and checkpoint identity
126
- * atomically before advancing the logical actor head. The host mailbox
245
+ * atomically before advancing the logical actor head. When settlement authority
246
+ * is present, that same transaction must also verify and close the exact
247
+ * suspension/resume-attempt fence, including stale-head outcomes. Retrying an
248
+ * ambiguous acknowledgement must return the durable outcome rather than apply
249
+ * the same terminal transition again. The host mailbox
127
250
  * deduplicates the logical `invocationId` before entering this seam, while each
128
251
  * SDK execution attempt receives a distinct checkpoint namespace. Preparation
129
252
  * methods own rollback until they return a ready invocation and must treat the
@@ -137,11 +260,28 @@ export interface EventActorDiscardRequest {
137
260
  * fork: the SDK retains and surfaces it as `commit_conflict` for host
138
261
  * reconciliation. `discard` must be idempotent for the same invocation because
139
262
  * an ambiguous cleanup failure can be retried through the public lifecycle.
263
+ *
264
+ * Suspension-capable hosts implement all optional suspension methods. `suspend`
265
+ * publishes an initial suspension only while its logical invocation is current;
266
+ * with `previous`, it atomically replaces only the exact claimed predecessor.
267
+ * `resume` atomically claims the current suspension before applying its value to
268
+ * the declared interrupt and rejects duplicate or competing claims as `stale`.
269
+ * It must return `claimed_failed` only when it can prove no qualifying action;
270
+ * any failure after an action returns `applied`. `settleSuspension` atomically
271
+ * discards the claimed fork and closes its fence for definite no-action
272
+ * outcomes. `cancelSuspension`
273
+ * atomically claims, discards, and closes current state, including expired
274
+ * evidence; expiration alone never implies a safe action outcome.
140
275
  */
141
276
  export interface EventActorHostAdapter<TEvent extends EventActorEvent, TResult extends EventActorEvent> {
142
277
  prepare(request: EventActorAdapterPrepareRequest<TEvent>, context: EventActorPreparationContext): Promise<EventActorAdapterPreparation<TEvent>>;
143
278
  coldContinue(request: EventActorAdapterPrepareRequest<TEvent>, head: EventActorHead, context: EventActorPreparationContext): Promise<EventActorInvocation<TEvent>>;
144
- invoke(invocation: EventActorInvocation<TEvent>, context: EventActorInvocationContext): Promise<EventActorTerminalResult<TResult>>;
279
+ invoke(invocation: EventActorInvocation<TEvent>, context: EventActorInvocationContext): Promise<EventActorAdapterInvocationResult<TResult>>;
280
+ suspend?(request: EventActorSuspendRequest): Promise<EventActorSuspendResult>;
281
+ resume?(request: EventActorAdapterResumeRequest, context: EventActorInvocationContext): Promise<EventActorAdapterResumeResult<TResult>>;
282
+ /** Atomically claims, discards, and closes the current suspension. */
283
+ cancelSuspension?(request: EventActorAdapterCancelSuspensionRequest, context: EventActorPreparationContext): Promise<EventActorAdapterCancelSuspensionResult>;
284
+ settleSuspension?(request: EventActorSettleSuspensionRequest): Promise<EventActorSettleSuspensionResult>;
145
285
  commit(request: EventActorCommitRequest<TResult>): Promise<EventActorCommitResult>;
146
286
  discard(request: EventActorDiscardRequest): Promise<void>;
147
287
  }
@@ -165,7 +305,9 @@ export type EventActorExecutionResult<TResult extends EventActorEvent> = {
165
305
  } | {
166
306
  status: 'cancelled';
167
307
  continuation: 'warm' | 'cold';
168
- } | {
308
+ } | (EventActorSuspendedResult & {
309
+ continuation: 'warm' | 'cold';
310
+ }) | {
169
311
  /** The action happened, but another head won the CAS. Reconcile; do not retry. */
170
312
  status: 'commit_conflict';
171
313
  result: TResult;
@@ -190,4 +332,6 @@ export interface EventActorExecutorOptions {
190
332
  dormantCheckpointTtlMs?: number;
191
333
  /** Stable private key of at least 32 bytes for cross-lifetime handoffs. */
192
334
  preparationSigningKey?: string | Uint8Array;
335
+ /** Maximum UTF-8 byte size of canonical suspension evidence. */
336
+ maxSuspensionPayloadBytes?: number;
193
337
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "3.7.5",
3
+ "version": "3.7.7",
4
4
  "reova": {
5
5
  "enabled": true,
6
6
  "endpoint": "https://telemetry.reo.dev/data"