@nocobase/plugin-ai 2.0.17 → 2.0.18

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,595 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var saver_exports = {};
28
+ __export(saver_exports, {
29
+ SequelizeCollectionSaver: () => SequelizeCollectionSaver
30
+ });
31
+ module.exports = __toCommonJS(saver_exports);
32
+ var import_langgraph_checkpoint = require("@langchain/langgraph-checkpoint");
33
+ var import_database = require("@nocobase/database");
34
+ class SequelizeCollectionSaver extends import_langgraph_checkpoint.BaseCheckpointSaver {
35
+ constructor(provideCollectionManager, serde) {
36
+ super(serde);
37
+ this.provideCollectionManager = provideCollectionManager;
38
+ }
39
+ async getTuple(config) {
40
+ var _a, _b;
41
+ const { thread_id, checkpoint_ns = "", checkpoint_id } = config.configurable ?? {};
42
+ let findOptions;
43
+ if (checkpoint_id) {
44
+ findOptions = {
45
+ where: {
46
+ threadId: thread_id,
47
+ checkpointNs: checkpoint_ns,
48
+ checkpointId: checkpoint_id
49
+ }
50
+ };
51
+ } else {
52
+ findOptions = {
53
+ where: {
54
+ threadId: thread_id,
55
+ checkpointNs: checkpoint_ns
56
+ },
57
+ order: [["checkpointId", "DESC"]],
58
+ limit: 1
59
+ };
60
+ }
61
+ const checkpointRow = (_a = await this.checkpointsModel.findOne(findOptions)) == null ? void 0 : _a.toJSON();
62
+ if (!checkpointRow) {
63
+ return void 0;
64
+ }
65
+ const { threadId, checkpointNs, checkpointId, parentCheckpointId } = checkpointRow;
66
+ checkpointRow.channelValues = [];
67
+ for (const [channel, version] of Object.entries(checkpointRow.checkpoint.channel_versions ?? {})) {
68
+ const blob = (_b = await this.checkpointBlobsModel.findOne({
69
+ where: {
70
+ threadId,
71
+ checkpointNs,
72
+ channel,
73
+ version: String(version)
74
+ }
75
+ })) == null ? void 0 : _b.toJSON();
76
+ if (!blob) {
77
+ continue;
78
+ }
79
+ checkpointRow.channelValues.push([
80
+ new TextEncoder().encode(blob.channel),
81
+ new TextEncoder().encode(blob.type),
82
+ blob.blob ? Uint8Array.from(blob.blob) : null
83
+ ]);
84
+ }
85
+ const checkpointWrites = await this.getCheckpointWrites([threadId], checkpointNs, checkpointId);
86
+ checkpointRow.pendingWrites = checkpointWrites[`${threadId}:${checkpointNs}:${checkpointId}`];
87
+ if (checkpointRow.checkpoint.v < 4 && checkpointRow.parentCheckpointId != null) {
88
+ const sendsResult = await this.getPendingSends([threadId]);
89
+ const pendingSends = sendsResult[`${threadId}:${parentCheckpointId}`];
90
+ if (pendingSends == null ? void 0 : pendingSends.length) {
91
+ await this._migratePendingSends(pendingSends, checkpointRow);
92
+ }
93
+ }
94
+ const checkpoint = await this._loadCheckpoint(checkpointRow.checkpoint, checkpointRow.channelValues);
95
+ const finalConfig = {
96
+ configurable: {
97
+ thread_id,
98
+ checkpoint_ns,
99
+ checkpoint_id: checkpointId
100
+ }
101
+ };
102
+ const metadata = await this._loadMetadata(checkpointRow.metadata);
103
+ const parentConfig = parentCheckpointId ? {
104
+ configurable: {
105
+ thread_id,
106
+ checkpoint_ns,
107
+ checkpoint_id: parentCheckpointId
108
+ }
109
+ } : void 0;
110
+ const pendingWrites = await this._loadWrites(checkpointRow.pendingWrites);
111
+ return {
112
+ config: finalConfig,
113
+ checkpoint,
114
+ metadata,
115
+ parentConfig,
116
+ pendingWrites
117
+ };
118
+ }
119
+ async *list(config, options) {
120
+ const { filter, before, limit } = options ?? {};
121
+ const findOptions = this._searchWhere(config, filter, before);
122
+ findOptions.order = [["checkpointId", "DESC"]];
123
+ if (limit !== void 0) {
124
+ findOptions.limit = Number.parseInt(limit.toString(), 10);
125
+ }
126
+ const result = (await this.checkpointsModel.findAll(findOptions)).map((x) => x.toJSON());
127
+ const [checkpointWrites, checkpointBlobs] = await Promise.all([
128
+ this.getCheckpointWrites(result.map((x) => x.threadId)),
129
+ this.getCheckpointBlobs(result.map((x) => x.threadId))
130
+ ]);
131
+ for (const checkpointRow of result) {
132
+ const { threadId, checkpointNs, checkpointId } = checkpointRow;
133
+ checkpointRow.channelValues = Object.entries(checkpointRow.checkpoint.channel_versions ?? {}).map(([channel, version]) => checkpointBlobs[`${threadId}:${checkpointNs}:${channel}:${version}`]).filter((x) => x == null ? void 0 : x.length).flatMap((x) => [...x]);
134
+ checkpointRow.pendingWrites = checkpointWrites[`${threadId}:${checkpointNs}:${checkpointId}`];
135
+ }
136
+ const toMigrate = result.filter((row) => row.checkpoint.v < 4 && row.parentCheckpointId != null);
137
+ if (toMigrate.length > 0) {
138
+ const sendsResult = await this.getPendingSends(result.map((x) => x.threadId));
139
+ for (const row of toMigrate) {
140
+ const pendingSends = sendsResult[`${row.threadId}:${row.parentCheckpointId}`];
141
+ if (pendingSends == null ? void 0 : pendingSends.length) {
142
+ await this._migratePendingSends(pendingSends, row);
143
+ }
144
+ }
145
+ }
146
+ for (const value of result) {
147
+ yield {
148
+ config: {
149
+ configurable: {
150
+ thread_id: value.threadId,
151
+ checkpoint_ns: value.checkpointNs,
152
+ checkpoint_id: value.checkpointId
153
+ }
154
+ },
155
+ checkpoint: await this._loadCheckpoint(value.checkpoint, value.channelValues),
156
+ metadata: await this._loadMetadata(value.metadata),
157
+ parentConfig: value.parentCheckpointId ? {
158
+ configurable: {
159
+ thread_id: value.threadId,
160
+ checkpoint_ns: value.checkpointNs,
161
+ checkpoint_id: value.parentCheckpointId
162
+ }
163
+ } : void 0,
164
+ pendingWrites: await this._loadWrites(value.pendingWrites)
165
+ };
166
+ }
167
+ }
168
+ async _migratePendingSends(pendingSends, mutableRow) {
169
+ const textEncoder = new TextEncoder();
170
+ const textDecoder = new TextDecoder();
171
+ const row = mutableRow;
172
+ const [enc, blob] = await this.serde.dumpsTyped(
173
+ await Promise.all(pendingSends.map(([enc2, blob2]) => this.serde.loadsTyped(textDecoder.decode(enc2), blob2)))
174
+ );
175
+ row.channelValues ??= [];
176
+ row.channelValues.push([textEncoder.encode(import_langgraph_checkpoint.TASKS), textEncoder.encode(enc), blob]);
177
+ row.checkpoint.channel_versions[import_langgraph_checkpoint.TASKS] = Object.keys(mutableRow.checkpoint.channel_versions).length > 0 ? (0, import_langgraph_checkpoint.maxChannelVersion)(...Object.values(mutableRow.checkpoint.channel_versions)) : this.getNextVersion(void 0);
178
+ }
179
+ async put(config, checkpoint, metadata, newVersions) {
180
+ if (config.configurable === void 0) {
181
+ throw new Error(`Missing "configurable" field in "config" param`);
182
+ }
183
+ const { thread_id, checkpoint_ns = "", checkpoint_id } = config.configurable;
184
+ const nextConfig = {
185
+ configurable: {
186
+ thread_id,
187
+ checkpoint_ns,
188
+ checkpoint_id: checkpoint.id
189
+ }
190
+ };
191
+ const serializedCheckpoint = this._dumpCheckpoint(checkpoint);
192
+ const serializedBlobs = await this._dumpBlobs(thread_id, checkpoint_ns, checkpoint.channel_values, newVersions);
193
+ const serializedMetadata = await this._dumpMetadata(metadata);
194
+ return await this.sequelize.transaction(async (transaction) => {
195
+ const checkpointBlobs = await this.checkpointBlobsModel.findAll({
196
+ where: {
197
+ threadId: thread_id,
198
+ checkpointNs: checkpoint_ns
199
+ },
200
+ attributes: {
201
+ exclude: ["blob"]
202
+ },
203
+ transaction
204
+ });
205
+ const duplicateBlobsFilter = checkpointBlobs.map(({ channel, version }) => `${channel}:${version}`);
206
+ await this.checkpointBlobsModel.bulkCreate(
207
+ serializedBlobs.filter(
208
+ ([_threadId, _checkpointNs, channel, version]) => !duplicateBlobsFilter.includes(`${channel}:${version}`)
209
+ ).map(([threadId, checkpointNs, channel, version, type, blob]) => ({
210
+ threadId,
211
+ checkpointNs,
212
+ channel,
213
+ version,
214
+ type,
215
+ blob: blob ? Buffer.from(blob) : null
216
+ })),
217
+ {
218
+ transaction
219
+ }
220
+ );
221
+ const checkPointFindOptions = {
222
+ where: { threadId: thread_id, checkpointNs: checkpoint_ns, checkpointId: checkpoint.id },
223
+ transaction
224
+ };
225
+ const existed = await this.checkpointsModel.count(checkPointFindOptions);
226
+ if (existed === 0) {
227
+ await this.checkpointsModel.create(
228
+ {
229
+ threadId: thread_id,
230
+ checkpointNs: checkpoint_ns,
231
+ checkpointId: checkpoint.id,
232
+ parentCheckpointId: checkpoint_id,
233
+ checkpoint: serializedCheckpoint,
234
+ metadata: serializedMetadata
235
+ },
236
+ {
237
+ transaction
238
+ }
239
+ );
240
+ } else {
241
+ await this.checkpointsModel.update(
242
+ {
243
+ checkpoint: serializedCheckpoint,
244
+ metadata: serializedMetadata
245
+ },
246
+ {
247
+ transaction,
248
+ where: checkPointFindOptions.where
249
+ }
250
+ );
251
+ }
252
+ return nextConfig;
253
+ });
254
+ }
255
+ async putWrites(config, writes, taskId) {
256
+ var _a, _b, _c, _d;
257
+ if (!((_a = config.configurable) == null ? void 0 : _a.thread_id)) {
258
+ throw new Error("config.configurable.thread_id is required");
259
+ }
260
+ const dumpedWrites = await this._dumpWrites(
261
+ (_b = config.configurable) == null ? void 0 : _b.thread_id,
262
+ (_c = config.configurable) == null ? void 0 : _c.checkpoint_ns,
263
+ (_d = config.configurable) == null ? void 0 : _d.checkpoint_id,
264
+ taskId,
265
+ writes
266
+ );
267
+ return await this.sequelize.transaction(async (transaction) => {
268
+ var _a2, _b2, _c2;
269
+ const checkpointWrites = await this.checkpointWritesModel.findAll({
270
+ where: {
271
+ threadId: (_a2 = config.configurable) == null ? void 0 : _a2.thread_id,
272
+ checkpointNs: (_b2 = config.configurable) == null ? void 0 : _b2.checkpoint_ns,
273
+ checkpointId: (_c2 = config.configurable) == null ? void 0 : _c2.checkpoint_id,
274
+ taskId
275
+ },
276
+ attributes: {
277
+ exclude: ["blob"]
278
+ },
279
+ transaction
280
+ });
281
+ const duplicateWritesFilter = checkpointWrites.map(
282
+ ({ threadId, checkpointNs, checkpointId, taskId: taskId2, idx }) => `${threadId}:${checkpointNs}:${checkpointId}:${taskId2}:${idx}`
283
+ );
284
+ const dumpedWritesInclude = ([threadId, checkpointNs, checkpointId, taskId2, idx]) => duplicateWritesFilter.includes(`${threadId}:${checkpointNs}:${checkpointId}:${taskId2}:${idx}`);
285
+ const dumpedWritesExclude = (item) => !dumpedWritesInclude(item);
286
+ await this.checkpointWritesModel.bulkCreate(
287
+ dumpedWrites.filter(dumpedWritesExclude).map(([threadId, checkpointNs, checkpointId, taskId2, idx, channel, type, blob]) => ({
288
+ threadId,
289
+ checkpointNs,
290
+ checkpointId,
291
+ taskId: taskId2,
292
+ idx,
293
+ channel,
294
+ type,
295
+ blob: blob ? Buffer.from(blob) : null
296
+ })),
297
+ {
298
+ transaction
299
+ }
300
+ );
301
+ for (const [threadId, checkpointNs, checkpointId, taskId2, idx, channel, type, blob] of dumpedWrites.filter(
302
+ dumpedWritesInclude
303
+ )) {
304
+ await this.checkpointWritesModel.update(
305
+ {
306
+ channel,
307
+ type,
308
+ blob: blob ? Buffer.from(blob) : null
309
+ },
310
+ {
311
+ where: {
312
+ threadId,
313
+ checkpointNs,
314
+ checkpointId,
315
+ taskId: taskId2,
316
+ idx
317
+ },
318
+ transaction
319
+ }
320
+ );
321
+ }
322
+ });
323
+ }
324
+ deleteThread(threadId) {
325
+ return this.sequelize.transaction(async (transaction) => {
326
+ await this.checkpointsModel.destroy({
327
+ where: {
328
+ threadId
329
+ },
330
+ transaction
331
+ });
332
+ await this.checkpointBlobsModel.destroy({
333
+ where: {
334
+ threadId
335
+ },
336
+ transaction
337
+ });
338
+ await this.checkpointWritesModel.destroy({
339
+ where: {
340
+ threadId
341
+ },
342
+ transaction
343
+ });
344
+ });
345
+ }
346
+ async _loadCheckpoint(checkpoint, channelValues) {
347
+ return {
348
+ ...checkpoint,
349
+ channel_values: await this._loadBlobs(channelValues)
350
+ };
351
+ }
352
+ async _loadBlobs(blobValues) {
353
+ if (!blobValues || blobValues.length === 0) {
354
+ return {};
355
+ }
356
+ const textDecoder = new TextDecoder();
357
+ const entries = await Promise.all(
358
+ blobValues.filter(([, t]) => textDecoder.decode(t) !== "empty").map(async ([k, t, v]) => [textDecoder.decode(k), await this.serde.loadsTyped(textDecoder.decode(t), v)])
359
+ );
360
+ return Object.fromEntries(entries);
361
+ }
362
+ async _loadMetadata(metadata) {
363
+ const [type, dumpedValue] = await this.serde.dumpsTyped(metadata);
364
+ return this.serde.loadsTyped(type, dumpedValue);
365
+ }
366
+ async _loadWrites(writes) {
367
+ const decoder = new TextDecoder();
368
+ return writes ? await Promise.all(
369
+ writes.map(async ([tid, channel, t, v]) => [
370
+ decoder.decode(tid),
371
+ decoder.decode(channel),
372
+ await this.serde.loadsTyped(decoder.decode(t), v)
373
+ ])
374
+ ) : [];
375
+ }
376
+ async _dumpBlobs(threadId, checkpointNs, values, versions) {
377
+ if (Object.keys(versions).length === 0) {
378
+ return [];
379
+ }
380
+ return Promise.all(
381
+ Object.entries(versions).map(async ([k, ver]) => {
382
+ const [type, value] = k in values ? await this.serde.dumpsTyped(values[k]) : ["empty", null];
383
+ return [threadId, checkpointNs, k, ver.toString(), type, value ? new Uint8Array(value) : void 0];
384
+ })
385
+ );
386
+ }
387
+ _dumpCheckpoint(checkpoint) {
388
+ const serialized = { ...checkpoint };
389
+ if ("channel_values" in serialized) delete serialized.channel_values;
390
+ return serialized;
391
+ }
392
+ async _dumpMetadata(metadata) {
393
+ const [, serializedMetadata] = await this.serde.dumpsTyped(metadata);
394
+ return JSON.parse(new TextDecoder().decode(serializedMetadata).replace(/\0/g, ""));
395
+ }
396
+ async _dumpWrites(threadId, checkpointNs, checkpointId, taskId, writes) {
397
+ return Promise.all(
398
+ writes.map(async ([channel, value], idx) => {
399
+ const [type, serializedValue] = await this.serde.dumpsTyped(value);
400
+ return [
401
+ threadId,
402
+ checkpointNs,
403
+ checkpointId,
404
+ taskId,
405
+ import_langgraph_checkpoint.WRITES_IDX_MAP[channel] ?? idx,
406
+ channel,
407
+ type,
408
+ new Uint8Array(serializedValue)
409
+ ];
410
+ })
411
+ );
412
+ }
413
+ _searchWhere(config, filter, before) {
414
+ var _a, _b, _c, _d, _e;
415
+ const findOptions = {};
416
+ if ((_a = config == null ? void 0 : config.configurable) == null ? void 0 : _a.thread_id) {
417
+ if (!findOptions.where) {
418
+ findOptions.where = {};
419
+ }
420
+ findOptions.where["threadId"] = config.configurable.thread_id;
421
+ }
422
+ if (((_b = config == null ? void 0 : config.configurable) == null ? void 0 : _b.checkpoint_ns) !== void 0 && ((_c = config == null ? void 0 : config.configurable) == null ? void 0 : _c.checkpoint_ns) !== null) {
423
+ if (!findOptions.where) {
424
+ findOptions.where = {};
425
+ }
426
+ findOptions.where["checkpointNs"] = config.configurable.checkpoint_ns;
427
+ }
428
+ if ((_d = config == null ? void 0 : config.configurable) == null ? void 0 : _d.checkpoint_id) {
429
+ if (!findOptions.where) {
430
+ findOptions.where = {};
431
+ }
432
+ findOptions.where["checkpointId"] = config.configurable.checkpoint_id;
433
+ }
434
+ if (filter && Object.keys(filter).length > 0) {
435
+ if (!findOptions.where) {
436
+ findOptions.where = {};
437
+ }
438
+ if (this.sequelize.getDialect() === "postgres") {
439
+ findOptions.where["metadata"] = {
440
+ [import_database.Op.contains]: filter
441
+ };
442
+ } else {
443
+ }
444
+ }
445
+ if (((_e = before == null ? void 0 : before.configurable) == null ? void 0 : _e.checkpoint_id) !== void 0) {
446
+ if (!findOptions.where) {
447
+ findOptions.where = {};
448
+ }
449
+ findOptions.where["checkpointId"] = {
450
+ $lt: before.configurable.checkpoint_id
451
+ };
452
+ }
453
+ return findOptions;
454
+ }
455
+ async getCheckpointWrites(threadIds, checkpointNs, checkpointId) {
456
+ if (!(threadIds == null ? void 0 : threadIds.length)) {
457
+ return {};
458
+ }
459
+ const where = {
460
+ threadId: threadIds.length === 1 ? threadIds[0] : {
461
+ [import_database.Op.in]: threadIds
462
+ }
463
+ };
464
+ if (checkpointNs) {
465
+ where["checkpointNs"] = checkpointNs;
466
+ }
467
+ if (checkpointId) {
468
+ where["checkpointId"] = checkpointId;
469
+ }
470
+ const writes = await this.checkpointWritesModel.findAll({
471
+ where
472
+ });
473
+ const result = {};
474
+ for (const write of writes) {
475
+ const key = `${write.threadId}:${write.checkpointNs}:${write.checkpointId}`;
476
+ if (!result[key]) {
477
+ result[key] = [];
478
+ }
479
+ result[key].push({
480
+ taskId: write.taskId,
481
+ channel: write.channel,
482
+ type: write.type,
483
+ blob: write.blob ? Uint8Array.from(write.blob) : null,
484
+ idx: write.idx
485
+ });
486
+ }
487
+ return Object.fromEntries(
488
+ Object.entries(result).map(([key, list]) => [
489
+ key,
490
+ [...list].sort((a, b) => {
491
+ if (a.taskId !== b.taskId) {
492
+ return a.taskId.localeCompare(b.taskId);
493
+ }
494
+ return a.idx - b.idx;
495
+ }).map(({ taskId, channel, type, blob }) => [
496
+ new TextEncoder().encode(taskId),
497
+ new TextEncoder().encode(channel),
498
+ new TextEncoder().encode(type),
499
+ blob
500
+ ])
501
+ ])
502
+ );
503
+ }
504
+ async getPendingSends(threadIds) {
505
+ if (!(threadIds == null ? void 0 : threadIds.length)) {
506
+ return {};
507
+ }
508
+ const writes = await this.checkpointWritesModel.findAll({
509
+ where: {
510
+ threadId: {
511
+ [import_database.Op.in]: threadIds
512
+ },
513
+ channel: import_langgraph_checkpoint.TASKS
514
+ }
515
+ });
516
+ const result = {};
517
+ for (const write of writes) {
518
+ const key = `${write.threadId}:${write.checkpointId}`;
519
+ if (!result[key]) {
520
+ result[key] = [];
521
+ }
522
+ result[key].push({
523
+ taskId: write.taskId,
524
+ channel: write.channel,
525
+ type: write.type,
526
+ blob: write.blob ? Uint8Array.from(write.blob) : null,
527
+ idx: write.idx
528
+ });
529
+ }
530
+ return Object.fromEntries(
531
+ Object.entries(result).map(([key, list]) => [
532
+ key,
533
+ [...list].sort((a, b) => {
534
+ if (a.taskId !== b.taskId) {
535
+ return a.taskId.localeCompare(b.taskId);
536
+ }
537
+ return a.idx - b.idx;
538
+ }).map(({ type, blob }) => [new TextEncoder().encode(type), blob])
539
+ ])
540
+ );
541
+ }
542
+ async getCheckpointBlobs(threadIds) {
543
+ const blobs = await this.checkpointBlobsModel.findAll({
544
+ where: {
545
+ threadId: threadIds.length === 1 ? threadIds[0] : {
546
+ [import_database.Op.in]: threadIds
547
+ }
548
+ }
549
+ });
550
+ const result = {};
551
+ for (const blob of blobs) {
552
+ const key = `${blob.threadId}:${blob.checkpointNs}:${blob.channel}:${blob.version}`;
553
+ if (!result[key]) {
554
+ result[key] = [];
555
+ }
556
+ result[key].push({
557
+ taskId: blob.taskId,
558
+ checkpointNs: blob.checkpointNs,
559
+ channel: blob.channel,
560
+ version: blob.version,
561
+ type: blob.type,
562
+ blob: blob.blob ? Uint8Array.from(blob.blob) : null
563
+ });
564
+ }
565
+ return Object.fromEntries(
566
+ Object.entries(result).map(([key, list]) => [
567
+ key,
568
+ list.map(({ channel, type, blob }) => [
569
+ new TextEncoder().encode(channel),
570
+ new TextEncoder().encode(type),
571
+ blob
572
+ ])
573
+ ])
574
+ );
575
+ }
576
+ get checkpointsModel() {
577
+ return this.collectionManager.getCollection("lcCheckpoints").model;
578
+ }
579
+ get checkpointBlobsModel() {
580
+ return this.collectionManager.getCollection("lcCheckpointBlobs").model;
581
+ }
582
+ get checkpointWritesModel() {
583
+ return this.collectionManager.getCollection("lcCheckpointWrites").model;
584
+ }
585
+ get sequelize() {
586
+ return this.collectionManager.db.sequelize;
587
+ }
588
+ get collectionManager() {
589
+ return this.provideCollectionManager().collectionManager;
590
+ }
591
+ }
592
+ // Annotate the CommonJS export names for ESM import in node:
593
+ 0 && (module.exports = {
594
+ SequelizeCollectionSaver
595
+ });
@@ -147,7 +147,7 @@ class BuiltInManager {
147
147
  const existedMap = new Map(existed.map((it) => [it.username, it.toJSON()]));
148
148
  for (const { username, description, skillSettings } of updates) {
149
149
  let { skills } = ((_a = existedMap.get(username)) == null ? void 0 : _a.skillSettings) ?? { skills: [] };
150
- skills = skills.filter((s) => {
150
+ skills = (skills ?? []).filter((s) => {
151
151
  var _a2;
152
152
  return (_a2 = s.name) == null ? void 0 : _a2.startsWith("workflowCaller-");
153
153
  });
@@ -67,6 +67,7 @@ var import_work_context_handler = require("./manager/work-context-handler");
67
67
  var import_ai_coding_manager = require("./manager/ai-coding-manager");
68
68
  var import_kimi = require("./llm-providers/kimi");
69
69
  var import_document_loader = require("./document-loader");
70
+ var import_checkpoints = require("./ai-employees/checkpoints");
70
71
  class PluginAIServer extends import_server.Plugin {
71
72
  features = new import_ai_feature_manager.AIPluginFeatureManagerImpl();
72
73
  aiManager = new import_ai_manager.AIManager(this);
@@ -94,6 +95,19 @@ class PluginAIServer extends import_server.Plugin {
94
95
  }
95
96
  });
96
97
  this.snowflake = new import_snowflake.default(pluginRecord == null ? void 0 : pluginRecord.createdAt.getTime());
98
+ this.app.cronJobManager.addJob({
99
+ cronTime: "0 0 2 * * *",
100
+ onTick: async () => {
101
+ try {
102
+ const checkpointSaver = new import_checkpoints.SequelizeCollectionSaver(() => this.app.mainDataSource);
103
+ const checkpointCleaner = new import_checkpoints.CheckpointCleaner(() => this.app.mainDataSource, checkpointSaver);
104
+ const expiredAt = new Date(Date.now() - 48 * 60 * 60 * 1e3);
105
+ await checkpointCleaner.cleanOutdated(expiredAt);
106
+ } catch (e) {
107
+ this.app.log.error("langChain checkpoint clean job fail", e);
108
+ }
109
+ }
110
+ });
97
111
  }
98
112
  async load() {
99
113
  await (0, import_tools.loadDocsIndexes)();
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "description": "Create AI employees with diverse skills to collaborate with humans, build systems, and handle business operations.",
7
7
  "description.ru-RU": "Поддержка интеграции с AI-сервисами: предоставляются AI-узлы для рабочих процессов, расширяя возможности бизнес-обработки.",
8
8
  "description.zh-CN": "创建各种技能的 AI 员工,与人类协同,搭建系统,处理业务。",
9
- "version": "2.0.17",
9
+ "version": "2.0.18",
10
10
  "license": "Apache-2.0",
11
11
  "main": "dist/server/index.js",
12
12
  "homepage": "https://docs.nocobase.com/handbook/action-ai",
@@ -60,5 +60,5 @@
60
60
  "keywords": [
61
61
  "AI"
62
62
  ],
63
- "gitHead": "3bf26e8a60d136a92fb0f6bba7eb621df48f03b6"
63
+ "gitHead": "f93082fd2c15618fe85e697a9cdd90614371732e"
64
64
  }