@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.
- package/dist/cjs/eventActor/EventActorExecutor.cjs +305 -11
- package/dist/cjs/eventActor/EventActorExecutor.cjs.map +1 -1
- package/dist/cjs/tools/search/keenable-search.cjs +7 -1
- package/dist/cjs/tools/search/keenable-search.cjs.map +1 -1
- package/dist/esm/eventActor/EventActorExecutor.mjs +305 -11
- package/dist/esm/eventActor/EventActorExecutor.mjs.map +1 -1
- package/dist/esm/tools/search/keenable-search.mjs +7 -1
- package/dist/esm/tools/search/keenable-search.mjs.map +1 -1
- package/dist/types/eventActor/EventActorExecutor.d.ts +3 -1
- package/dist/types/eventActor/index.d.ts +1 -1
- package/dist/types/eventActor/types.d.ts +149 -5
- package/package.json +1 -1
- package/src/eventActor/EventActorExecutor.ts +545 -16
- package/src/eventActor/index.ts +17 -0
- package/src/eventActor/types.ts +182 -3
- package/src/tools/search/keenable-search.ts +18 -1
package/src/eventActor/index.ts
CHANGED
|
@@ -5,7 +5,15 @@ export {
|
|
|
5
5
|
export type {
|
|
6
6
|
EventActorAdapterPrepareRequest,
|
|
7
7
|
EventActorAdapterPreparation,
|
|
8
|
+
EventActorAdapterInvocationResult,
|
|
9
|
+
EventActorAdapterResumeRequest,
|
|
10
|
+
EventActorAdapterResumeResult,
|
|
11
|
+
EventActorAdapterSuspendedResult,
|
|
8
12
|
EventActorAppliedResult,
|
|
13
|
+
EventActorAdapterCancelSuspensionRequest,
|
|
14
|
+
EventActorAdapterCancelSuspensionResult,
|
|
15
|
+
EventActorCancelSuspensionRequest,
|
|
16
|
+
EventActorCancelSuspensionResult,
|
|
9
17
|
EventActorCheckpointFork,
|
|
10
18
|
EventActorCheckpointReference,
|
|
11
19
|
EventActorCommitRequest,
|
|
@@ -21,12 +29,21 @@ export type {
|
|
|
21
29
|
EventActorInvocation,
|
|
22
30
|
EventActorInvocationContext,
|
|
23
31
|
EventActorIndeterminateResult,
|
|
32
|
+
EventActorInterrupt,
|
|
24
33
|
EventActorInvocationReference,
|
|
25
34
|
EventActorInvocationResult,
|
|
26
35
|
EventActorPreparation,
|
|
27
36
|
EventActorPreparationContext,
|
|
28
37
|
EventActorPreparedInvocation,
|
|
29
38
|
EventActorPrepareRequest,
|
|
39
|
+
EventActorResumeRequest,
|
|
40
|
+
EventActorSettleSuspensionRequest,
|
|
41
|
+
EventActorSettleSuspensionResult,
|
|
42
|
+
EventActorSettlementAuthority,
|
|
30
43
|
EventActorSettlementResult,
|
|
44
|
+
EventActorSuspendRequest,
|
|
45
|
+
EventActorSuspendResult,
|
|
46
|
+
EventActorSuspendedResult,
|
|
47
|
+
EventActorSuspension,
|
|
31
48
|
EventActorTerminalResult,
|
|
32
49
|
} from './types';
|
package/src/eventActor/types.ts
CHANGED
|
@@ -74,14 +74,156 @@ export type EventActorTerminalResult<TResult extends EventActorEvent> =
|
|
|
74
74
|
}
|
|
75
75
|
| { status: 'completed_no_action'; result?: TResult };
|
|
76
76
|
|
|
77
|
+
/** JSON-safe interrupt descriptor retained with a suspended invocation fork. */
|
|
78
|
+
export interface EventActorInterrupt<
|
|
79
|
+
TPayload extends EventActorEvent = EventActorEvent,
|
|
80
|
+
> {
|
|
81
|
+
id: string;
|
|
82
|
+
payload: TPayload;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Nonterminal adapter outcome. The checkpoint must already contain the pause;
|
|
87
|
+
* the SDK publishes its authority through `suspend` before exposing it.
|
|
88
|
+
*/
|
|
89
|
+
export interface EventActorAdapterSuspendedResult<
|
|
90
|
+
TPayload extends EventActorEvent = EventActorEvent,
|
|
91
|
+
> {
|
|
92
|
+
status: 'suspended';
|
|
93
|
+
checkpoint: EventActorCheckpointFork;
|
|
94
|
+
interrupt: EventActorInterrupt<TPayload>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export type EventActorAdapterInvocationResult<
|
|
98
|
+
TResult extends EventActorEvent,
|
|
99
|
+
TPayload extends EventActorEvent = EventActorEvent,
|
|
100
|
+
> =
|
|
101
|
+
| EventActorTerminalResult<TResult>
|
|
102
|
+
| EventActorAdapterSuspendedResult<TPayload>;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Authenticated, versioned, JSON-safe evidence for one nonterminal invocation.
|
|
106
|
+
* Integrity does not make this evidence one-shot; the host's durable current
|
|
107
|
+
* suspension record is the replay and ownership fence. Hosts must capability-
|
|
108
|
+
* route each exact version during rolling deploys and drain or migrate current
|
|
109
|
+
* evidence before rotating away from its signing key.
|
|
110
|
+
*/
|
|
111
|
+
export interface EventActorSuspension<
|
|
112
|
+
TPayload extends EventActorEvent = EventActorEvent,
|
|
113
|
+
> {
|
|
114
|
+
version: 1;
|
|
115
|
+
suspensionId: string;
|
|
116
|
+
attempt: number;
|
|
117
|
+
issuedAt: number;
|
|
118
|
+
expiresAt: number;
|
|
119
|
+
invocation: EventActorInvocationReference;
|
|
120
|
+
checkpoint: EventActorCheckpointFork;
|
|
121
|
+
interrupt: EventActorInterrupt<TPayload>;
|
|
122
|
+
suspensionDigest: string;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface EventActorSuspendedResult<
|
|
126
|
+
TPayload extends EventActorEvent = EventActorEvent,
|
|
127
|
+
> {
|
|
128
|
+
status: 'suspended';
|
|
129
|
+
suspension: EventActorSuspension<TPayload>;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface EventActorSuspendRequest {
|
|
133
|
+
suspension: EventActorSuspension;
|
|
134
|
+
/** CAS predecessor required when a claimed resume pauses again. */
|
|
135
|
+
previous?: {
|
|
136
|
+
suspensionId: string;
|
|
137
|
+
attempt: number;
|
|
138
|
+
resumeAttemptId: string;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export type EventActorSuspendResult =
|
|
143
|
+
| { status: 'stored' }
|
|
144
|
+
| { status: 'stale' };
|
|
145
|
+
|
|
146
|
+
export interface EventActorAdapterResumeRequest {
|
|
147
|
+
suspension: EventActorSuspension;
|
|
148
|
+
resumeAttemptId: string;
|
|
149
|
+
value: EventActorEvent;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export type EventActorAdapterResumeResult<TResult extends EventActorEvent> =
|
|
153
|
+
| {
|
|
154
|
+
status: 'claimed';
|
|
155
|
+
result: EventActorAdapterInvocationResult<TResult>;
|
|
156
|
+
}
|
|
157
|
+
| {
|
|
158
|
+
/** The host proved no action before returning this claimed failure. */
|
|
159
|
+
status: 'claimed_failed';
|
|
160
|
+
error: Error;
|
|
161
|
+
}
|
|
162
|
+
| { status: 'stale' };
|
|
163
|
+
|
|
164
|
+
export interface EventActorResumeRequest {
|
|
165
|
+
suspension: EventActorSuspension;
|
|
166
|
+
resumeAttemptId: string;
|
|
167
|
+
value: EventActorEvent;
|
|
168
|
+
signal?: AbortSignal;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface EventActorCancelSuspensionRequest {
|
|
172
|
+
suspension: EventActorSuspension;
|
|
173
|
+
cancelAttemptId: string;
|
|
174
|
+
reason?: 'cancelled' | 'expired';
|
|
175
|
+
signal?: AbortSignal;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface EventActorAdapterCancelSuspensionRequest {
|
|
179
|
+
suspension: EventActorSuspension;
|
|
180
|
+
cancelAttemptId: string;
|
|
181
|
+
reason: 'cancelled' | 'expired';
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export type EventActorCancelSuspensionResult =
|
|
185
|
+
| { status: 'cancelled' }
|
|
186
|
+
| EventActorIndeterminateResult<EventActorEvent>;
|
|
187
|
+
|
|
188
|
+
export type EventActorAdapterCancelSuspensionResult =
|
|
189
|
+
| { status: 'cancelled' }
|
|
190
|
+
| { status: 'stale' };
|
|
191
|
+
|
|
192
|
+
export interface EventActorSettleSuspensionRequest {
|
|
193
|
+
suspensionId: string;
|
|
194
|
+
attempt: number;
|
|
195
|
+
resumeAttemptId: string;
|
|
196
|
+
status: 'completed_no_action' | 'failed';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export type EventActorSettleSuspensionResult =
|
|
200
|
+
| { status: 'settled' }
|
|
201
|
+
| { status: 'stale' };
|
|
202
|
+
|
|
77
203
|
export type EventActorAppliedResult<TResult extends EventActorEvent> = Extract<
|
|
78
204
|
EventActorTerminalResult<TResult>,
|
|
79
205
|
{ status: 'applied' }
|
|
80
206
|
> & {
|
|
81
|
-
/** Executor-issued
|
|
207
|
+
/** Executor-issued settlement for the invocation that produced this action. */
|
|
82
208
|
invocation: EventActorInvocationReference;
|
|
209
|
+
/** Authenticated cross-executor authority for a resumed terminal action. */
|
|
210
|
+
settlementAuthority?: EventActorSettlementAuthority;
|
|
83
211
|
};
|
|
84
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Authenticated fence that binds a resumed terminal result to its claimed
|
|
215
|
+
* suspension. The host must consume it atomically with the actor-head CAS.
|
|
216
|
+
*/
|
|
217
|
+
export interface EventActorSettlementAuthority {
|
|
218
|
+
version: 1;
|
|
219
|
+
suspensionId: string;
|
|
220
|
+
attempt: number;
|
|
221
|
+
resumeAttemptId: string;
|
|
222
|
+
issuedAt: number;
|
|
223
|
+
expiresAt: number;
|
|
224
|
+
settlementDigest: string;
|
|
225
|
+
}
|
|
226
|
+
|
|
85
227
|
export interface EventActorIndeterminateResult<
|
|
86
228
|
TResult extends EventActorEvent,
|
|
87
229
|
> {
|
|
@@ -95,6 +237,7 @@ export interface EventActorIndeterminateResult<
|
|
|
95
237
|
export type EventActorInvocationResult<TResult extends EventActorEvent> =
|
|
96
238
|
| EventActorAppliedResult<TResult>
|
|
97
239
|
| EventActorIndeterminateResult<TResult>
|
|
240
|
+
| EventActorSuspendedResult
|
|
98
241
|
| Extract<
|
|
99
242
|
EventActorTerminalResult<TResult>,
|
|
100
243
|
{ status: 'completed_no_action' }
|
|
@@ -128,6 +271,8 @@ export interface EventActorCommitRequest<TResult extends EventActorEvent> {
|
|
|
128
271
|
expectedHead: EventActorHead;
|
|
129
272
|
checkpoint: EventActorCheckpointFork;
|
|
130
273
|
result: TResult;
|
|
274
|
+
/** Host must consume this suspension fence atomically with the head CAS. */
|
|
275
|
+
settlementAuthority?: EventActorSettlementAuthority;
|
|
131
276
|
retention: {
|
|
132
277
|
committedCheckpoints: 2;
|
|
133
278
|
dormantCheckpointTtlMs: number;
|
|
@@ -156,7 +301,11 @@ export interface EventActorDiscardRequest {
|
|
|
156
301
|
/**
|
|
157
302
|
* Host adapter for durable actor state and the concrete agent invocation.
|
|
158
303
|
* `commit` must compare both the expected generation and checkpoint identity
|
|
159
|
-
* atomically before advancing the logical actor head.
|
|
304
|
+
* atomically before advancing the logical actor head. When settlement authority
|
|
305
|
+
* is present, that same transaction must also verify and close the exact
|
|
306
|
+
* suspension/resume-attempt fence, including stale-head outcomes. Retrying an
|
|
307
|
+
* ambiguous acknowledgement must return the durable outcome rather than apply
|
|
308
|
+
* the same terminal transition again. The host mailbox
|
|
160
309
|
* deduplicates the logical `invocationId` before entering this seam, while each
|
|
161
310
|
* SDK execution attempt receives a distinct checkpoint namespace. Preparation
|
|
162
311
|
* methods own rollback until they return a ready invocation and must treat the
|
|
@@ -170,6 +319,18 @@ export interface EventActorDiscardRequest {
|
|
|
170
319
|
* fork: the SDK retains and surfaces it as `commit_conflict` for host
|
|
171
320
|
* reconciliation. `discard` must be idempotent for the same invocation because
|
|
172
321
|
* an ambiguous cleanup failure can be retried through the public lifecycle.
|
|
322
|
+
*
|
|
323
|
+
* Suspension-capable hosts implement all optional suspension methods. `suspend`
|
|
324
|
+
* publishes an initial suspension only while its logical invocation is current;
|
|
325
|
+
* with `previous`, it atomically replaces only the exact claimed predecessor.
|
|
326
|
+
* `resume` atomically claims the current suspension before applying its value to
|
|
327
|
+
* the declared interrupt and rejects duplicate or competing claims as `stale`.
|
|
328
|
+
* It must return `claimed_failed` only when it can prove no qualifying action;
|
|
329
|
+
* any failure after an action returns `applied`. `settleSuspension` atomically
|
|
330
|
+
* discards the claimed fork and closes its fence for definite no-action
|
|
331
|
+
* outcomes. `cancelSuspension`
|
|
332
|
+
* atomically claims, discards, and closes current state, including expired
|
|
333
|
+
* evidence; expiration alone never implies a safe action outcome.
|
|
173
334
|
*/
|
|
174
335
|
export interface EventActorHostAdapter<
|
|
175
336
|
TEvent extends EventActorEvent,
|
|
@@ -187,7 +348,20 @@ export interface EventActorHostAdapter<
|
|
|
187
348
|
invoke(
|
|
188
349
|
invocation: EventActorInvocation<TEvent>,
|
|
189
350
|
context: EventActorInvocationContext
|
|
190
|
-
): Promise<
|
|
351
|
+
): Promise<EventActorAdapterInvocationResult<TResult>>;
|
|
352
|
+
suspend?(request: EventActorSuspendRequest): Promise<EventActorSuspendResult>;
|
|
353
|
+
resume?(
|
|
354
|
+
request: EventActorAdapterResumeRequest,
|
|
355
|
+
context: EventActorInvocationContext
|
|
356
|
+
): Promise<EventActorAdapterResumeResult<TResult>>;
|
|
357
|
+
/** Atomically claims, discards, and closes the current suspension. */
|
|
358
|
+
cancelSuspension?(
|
|
359
|
+
request: EventActorAdapterCancelSuspensionRequest,
|
|
360
|
+
context: EventActorPreparationContext
|
|
361
|
+
): Promise<EventActorAdapterCancelSuspensionResult>;
|
|
362
|
+
settleSuspension?(
|
|
363
|
+
request: EventActorSettleSuspensionRequest
|
|
364
|
+
): Promise<EventActorSettleSuspensionResult>;
|
|
191
365
|
commit(
|
|
192
366
|
request: EventActorCommitRequest<TResult>
|
|
193
367
|
): Promise<EventActorCommitResult>;
|
|
@@ -219,6 +393,9 @@ export type EventActorExecutionResult<TResult extends EventActorEvent> =
|
|
|
219
393
|
status: 'cancelled';
|
|
220
394
|
continuation: 'warm' | 'cold';
|
|
221
395
|
}
|
|
396
|
+
| (EventActorSuspendedResult & {
|
|
397
|
+
continuation: 'warm' | 'cold';
|
|
398
|
+
})
|
|
222
399
|
| {
|
|
223
400
|
/** The action happened, but another head won the CAS. Reconcile; do not retry. */
|
|
224
401
|
status: 'commit_conflict';
|
|
@@ -247,4 +424,6 @@ export interface EventActorExecutorOptions {
|
|
|
247
424
|
dormantCheckpointTtlMs?: number;
|
|
248
425
|
/** Stable private key of at least 32 bytes for cross-lifetime handoffs. */
|
|
249
426
|
preparationSigningKey?: string | Uint8Array;
|
|
427
|
+
/** Maximum UTF-8 byte size of canonical suspension evidence. */
|
|
428
|
+
maxSuspensionPayloadBytes?: number;
|
|
250
429
|
}
|
|
@@ -16,6 +16,23 @@ const KEENABLE_DATE_RANGES: Record<DATE_RANGE, string> = {
|
|
|
16
16
|
[DATE_RANGE.PAST_YEAR]: '1y',
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
/** Characters of page text kept per result. Keenable returns the whole page on
|
|
20
|
+
* every search result, an order of magnitude more than the other providers here
|
|
21
|
+
* return, which would crowd out the reranker and the LLM output budget. */
|
|
22
|
+
const SNIPPET_MAX_LENGTH = 500;
|
|
23
|
+
|
|
24
|
+
/** Keenable sends both `description` and `snippet` on every result: `snippet`
|
|
25
|
+
* carries the page text and `description` is the page's meta description, which
|
|
26
|
+
* is empty for most pages. Either field can arrive as an empty string, so the
|
|
27
|
+
* pick is on emptiness rather than nullishness: a `??` chain would keep an empty
|
|
28
|
+
* `snippet` over a `description` that does carry text. */
|
|
29
|
+
function toSnippet(result: t.KeenableSearchResult): string {
|
|
30
|
+
const snippet = (result.snippet ?? '').replace(/\s+/g, ' ').trim();
|
|
31
|
+
const description = (result.description ?? '').replace(/\s+/g, ' ').trim();
|
|
32
|
+
const text = snippet !== '' ? snippet : description;
|
|
33
|
+
return text.slice(0, SNIPPET_MAX_LENGTH);
|
|
34
|
+
}
|
|
35
|
+
|
|
19
36
|
export const createKeenableAPI = (
|
|
20
37
|
apiKey?: string,
|
|
21
38
|
apiUrl?: string,
|
|
@@ -84,7 +101,7 @@ export const createKeenableAPI = (
|
|
|
84
101
|
const organic: t.OrganicResult[] = rawResults.map((result) => ({
|
|
85
102
|
title: result.title ?? '',
|
|
86
103
|
link: result.url ?? '',
|
|
87
|
-
snippet: result
|
|
104
|
+
snippet: toSnippet(result),
|
|
88
105
|
date: result.published_at,
|
|
89
106
|
}));
|
|
90
107
|
|