From 31af7baebd22ca596fc41b4a56ec6e936787205d Mon Sep 17 00:00:00 2001 From: Drol Date: Mon, 16 Mar 2026 11:11:01 +0800 Subject: [PATCH] feat(ai): auto clean up ai conversation`s checkpoint data (#8855) * feat(ai): add langChain checkpoints cleaner * feat(ai): add cron job for checkpoint cleaning --- .../ai-employees/checkpoints/cleaner.ts | 138 ++++ .../server/ai-employees/checkpoints/index.ts | 733 +---------------- .../server/ai-employees/checkpoints/saver.ts | 740 ++++++++++++++++++ .../@nocobase/plugin-ai/src/server/plugin.ts | 14 + yarn.lock | 377 +-------- 5 files changed, 906 insertions(+), 1096 deletions(-) create mode 100644 packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/cleaner.ts create mode 100644 packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/saver.ts diff --git a/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/cleaner.ts b/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/cleaner.ts new file mode 100644 index 00000000000..b1f8f4797be --- /dev/null +++ b/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/cleaner.ts @@ -0,0 +1,138 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +import { BaseCheckpointSaver } from '@langchain/langgraph-checkpoint'; +import { Op } from '@nocobase/database'; +import { SequelizeCollectionManager } from '@nocobase/data-source-manager'; + +export type AIConversationsType = { + sessionId: string; + thread: number; +}; + +export class CheckpointCleaner { + constructor( + private readonly provideCollectionManager: () => { collectionManager: SequelizeCollectionManager }, + private readonly checkpointSaver: BaseCheckpointSaver, + ) {} + + async cleanOutdated(expiredAt: Date) { + const outdatedConversations = await this.aiConversationsModel.findAll({ + attributes: ['sessionId', 'thread'], + where: { + updatedAt: { + [Op.lt]: expiredAt, + }, + thread: { + [Op.ne]: 0, + }, + }, + raw: true, + }); + + if (!outdatedConversations.length) { + return; + } + + const sessionIds = outdatedConversations.map((conversation) => conversation.sessionId); + const latestMessageRefs = await this.aiMessagesModel.findAll({ + attributes: ['sessionId', [this.sequelize.fn('MAX', this.sequelize.col('messageId')), 'messageId']], + where: { + sessionId: { + [Op.in]: sessionIds, + }, + }, + group: ['sessionId'], + raw: true, + }); + + if (!latestMessageRefs.length) { + return; + } + + const latestMessageIds = latestMessageRefs.map((row) => row.messageId); + const latestMessages = await this.aiMessagesModel.findAll({ + attributes: ['sessionId', 'updatedAt', 'toolCalls'], + where: { + messageId: { + [Op.in]: latestMessageIds, + }, + }, + raw: true, + }); + + const latestMessageMap = new Map(latestMessages.map((message) => [message.sessionId, message])); + const conversationsToClean: AIConversationsType[] = []; + for (const conversation of outdatedConversations) { + const latestMessage = latestMessageMap.get(conversation.sessionId); + if (!latestMessage) { + continue; + } + const latestMessageAt = latestMessage.updatedAt ? new Date(latestMessage.updatedAt) : undefined; + const hasToolCalls = Array.isArray(latestMessage.toolCalls) + ? latestMessage.toolCalls.length > 0 + : !!latestMessage.toolCalls; + if (latestMessageAt && latestMessageAt < expiredAt && !hasToolCalls) { + conversationsToClean.push(conversation as unknown as AIConversationsType); + } + } + + if (!conversationsToClean.length) { + return; + } + + await this.clean(conversationsToClean); + } + + async clean(conversations: AIConversationsType[]): Promise { + if (!conversations?.length) { + return; + } + const threadIds = this.getThreadIds(conversations); + await this.aiConversationsModel.update( + { thread: 0 }, + { + where: { + sessionId: { + [Op.in]: conversations.map((x) => x.sessionId), + }, + }, + }, + ); + for (const threadId of threadIds) { + await this.checkpointSaver.deleteThread(threadId); + } + } + + private getThreadIds(conversations: AIConversationsType[]): string[] { + const threadIds = []; + for (const conversation of conversations) { + for (let i = conversation.thread; i > 0; i--) { + threadIds.push(`${conversation.sessionId}:${i}`); + } + } + return threadIds; + } + + private get aiConversationsModel() { + return this.collectionManager.getCollection('aiConversations').model; + } + + private get aiMessagesModel() { + return this.collectionManager.getCollection('aiMessages').model; + } + + private get sequelize() { + return this.collectionManager.db.sequelize; + } + + private get collectionManager() { + return this.provideCollectionManager().collectionManager; + } +} diff --git a/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/index.ts b/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/index.ts index 2dc5c3559d0..dc8bb19017b 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/index.ts +++ b/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/index.ts @@ -7,734 +7,5 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import { RunnableConfig } from '@langchain/core/runnables'; -import { - BaseCheckpointSaver, - ChannelVersions, - Checkpoint, - CheckpointListOptions, - CheckpointMetadata, - CheckpointTuple, - maxChannelVersion, - PendingWrite, - SerializerProtocol, - TASKS, - WRITES_IDX_MAP, -} from '@langchain/langgraph-checkpoint'; -import { SequelizeCollectionManager } from '@nocobase/data-source-manager'; -import { FindOptions, Op } from '@nocobase/database'; - -export class SequelizeCollectionSaver extends BaseCheckpointSaver { - constructor( - private readonly provideCollectionManager: () => { collectionManager: SequelizeCollectionManager }, - serde?: SerializerProtocol, - ) { - super(serde); - } - - async getTuple(config: RunnableConfig): Promise { - const { thread_id, checkpoint_ns = '', checkpoint_id } = config.configurable ?? {}; - - let findOptions: FindOptions; - if (checkpoint_id) { - findOptions = { - where: { - threadId: thread_id, - checkpointNs: checkpoint_ns, - checkpointId: checkpoint_id, - }, - }; - } else { - findOptions = { - where: { - threadId: thread_id, - checkpointNs: checkpoint_ns, - }, - order: [['checkpointId', 'DESC']], - limit: 1, - }; - } - - const checkpointRow = (await this.checkpointsModel.findOne(findOptions))?.toJSON(); - if (!checkpointRow) { - return undefined; - } - const { threadId, checkpointNs, checkpointId, parentCheckpointId } = checkpointRow; - - checkpointRow.channelValues = []; - for (const [channel, version] of Object.entries(checkpointRow.checkpoint.channel_versions ?? {})) { - const blob = ( - await this.checkpointBlobsModel.findOne({ - where: { - threadId, - checkpointNs, - channel, - version: String(version), - }, - }) - )?.toJSON(); - if (!blob) { - continue; - } - checkpointRow.channelValues.push([ - new TextEncoder().encode(blob.channel), - new TextEncoder().encode(blob.type), - blob.blob ? Uint8Array.from(blob.blob) : null, - ]); - } - - const checkpointWrites = await this.getCheckpointWrites([threadId], checkpointNs, checkpointId); - checkpointRow.pendingWrites = checkpointWrites[`${threadId}:${checkpointNs}:${checkpointId}`]; - - if (checkpointRow.checkpoint.v < 4 && checkpointRow.parentCheckpointId != null) { - const sendsResult = await this.getPendingSends([threadId]); - const pendingSends = sendsResult[`${threadId}:${parentCheckpointId}`]; - if (pendingSends?.length) { - await this._migratePendingSends(pendingSends, checkpointRow); - } - } - - const checkpoint = await this._loadCheckpoint(checkpointRow.checkpoint, checkpointRow.channelValues); - - const finalConfig = { - configurable: { - thread_id, - checkpoint_ns, - checkpoint_id: checkpointId, - }, - }; - const metadata = await this._loadMetadata(checkpointRow.metadata); - const parentConfig = parentCheckpointId - ? { - configurable: { - thread_id, - checkpoint_ns, - checkpoint_id: parentCheckpointId, - }, - } - : undefined; - - const pendingWrites = await this._loadWrites(checkpointRow.pendingWrites); - - return { - config: finalConfig, - checkpoint, - metadata, - parentConfig, - pendingWrites, - }; - } - - async *list(config: RunnableConfig, options?: CheckpointListOptions): AsyncGenerator { - const { filter, before, limit } = options ?? {}; - const findOptions = this._searchWhere(config, filter, before); - findOptions.order = [['checkpointId', 'DESC']]; - if (limit !== undefined) { - findOptions.limit = Number.parseInt(limit.toString(), 10); // sanitize via parseInt, as limit could be an externally provided value - } - - const result = (await this.checkpointsModel.findAll(findOptions)).map((x) => x.toJSON()); - const [checkpointWrites, checkpointBlobs] = await Promise.all([ - this.getCheckpointWrites(result.map((x) => x.threadId)), - this.getCheckpointBlobs(result.map((x) => x.threadId)), - ]); - - for (const checkpointRow of result) { - const { threadId, checkpointNs, checkpointId } = checkpointRow; - checkpointRow.channelValues = Object.entries(checkpointRow.checkpoint.channel_versions ?? {}) - .map(([channel, version]) => checkpointBlobs[`${threadId}:${checkpointNs}:${channel}:${version}`]) - .filter((x) => x?.length) - .flatMap((x) => [...x]); - checkpointRow.pendingWrites = checkpointWrites[`${threadId}:${checkpointNs}:${checkpointId}`]; - } - const toMigrate = result.filter((row) => row.checkpoint.v < 4 && row.parentCheckpointId != null); - - if (toMigrate.length > 0) { - const sendsResult = await this.getPendingSends(result.map((x) => x.threadId)); - for (const row of toMigrate) { - const pendingSends = sendsResult[`${row.threadId}:${row.parentCheckpointId}`]; - if (pendingSends?.length) { - await this._migratePendingSends(pendingSends, row); - } - } - } - - for (const value of result) { - yield { - config: { - configurable: { - thread_id: value.threadId, - checkpoint_ns: value.checkpointNs, - checkpoint_id: value.checkpointId, - }, - }, - checkpoint: await this._loadCheckpoint(value.checkpoint, value.channelValues), - metadata: await this._loadMetadata(value.metadata), - parentConfig: value.parentCheckpointId - ? { - configurable: { - thread_id: value.threadId, - checkpoint_ns: value.checkpointNs, - checkpoint_id: value.parentCheckpointId, - }, - } - : undefined, - pendingWrites: await this._loadWrites(value.pendingWrites), - }; - } - } - - async _migratePendingSends( - pendingSends: [Uint8Array, Uint8Array][], - mutableRow: { - channelValues: [Uint8Array, Uint8Array, Uint8Array][]; - checkpoint: Omit; - }, - ) { - const textEncoder = new TextEncoder(); - const textDecoder = new TextDecoder(); - const row = mutableRow; - - const [enc, blob] = await this.serde.dumpsTyped( - await Promise.all(pendingSends.map(([enc, blob]) => this.serde.loadsTyped(textDecoder.decode(enc), blob))), - ); - - row.channelValues ??= []; - row.channelValues.push([textEncoder.encode(TASKS), textEncoder.encode(enc), blob]); - - // add to versions - row.checkpoint.channel_versions[TASKS] = - Object.keys(mutableRow.checkpoint.channel_versions).length > 0 - ? maxChannelVersion(...Object.values(mutableRow.checkpoint.channel_versions)) - : this.getNextVersion(undefined); - } - - async put( - config: RunnableConfig, - checkpoint: Checkpoint, - metadata: CheckpointMetadata, - newVersions: ChannelVersions, - ): Promise { - if (config.configurable === undefined) { - throw new Error(`Missing "configurable" field in "config" param`); - } - const { thread_id, checkpoint_ns = '', checkpoint_id } = config.configurable; - - const nextConfig = { - configurable: { - thread_id, - checkpoint_ns, - checkpoint_id: checkpoint.id, - }, - }; - const serializedCheckpoint = this._dumpCheckpoint(checkpoint); - const serializedBlobs = await this._dumpBlobs(thread_id, checkpoint_ns, checkpoint.channel_values, newVersions); - const serializedMetadata = await this._dumpMetadata(metadata); - - return await this.sequelize.transaction(async (transaction) => { - const checkpointBlobs = await this.checkpointBlobsModel.findAll({ - where: { - threadId: thread_id, - checkpointNs: checkpoint_ns, - }, - attributes: { - exclude: ['blob'], - }, - transaction, - }); - const duplicateBlobsFilter = checkpointBlobs.map(({ channel, version }) => `${channel}:${version}`); - - await this.checkpointBlobsModel.bulkCreate( - serializedBlobs - .filter( - ([_threadId, _checkpointNs, channel, version]) => !duplicateBlobsFilter.includes(`${channel}:${version}`), - ) - .map(([threadId, checkpointNs, channel, version, type, blob]) => ({ - threadId, - checkpointNs, - channel, - version, - type, - blob: blob ? Buffer.from(blob) : null, - })), - { - transaction, - }, - ); - - const checkPointFindOptions: FindOptions = { - where: { threadId: thread_id, checkpointNs: checkpoint_ns, checkpointId: checkpoint.id }, - transaction, - }; - const existed = await this.checkpointsModel.count(checkPointFindOptions); - if (existed === 0) { - await this.checkpointsModel.create( - { - threadId: thread_id, - checkpointNs: checkpoint_ns, - checkpointId: checkpoint.id, - parentCheckpointId: checkpoint_id, - checkpoint: serializedCheckpoint, - metadata: serializedMetadata, - }, - { - transaction, - }, - ); - } else { - await this.checkpointsModel.update( - { - checkpoint: serializedCheckpoint, - metadata: serializedMetadata, - }, - { - transaction, - where: checkPointFindOptions.where, - }, - ); - } - - return nextConfig; - }); - } - async putWrites(config: RunnableConfig, writes: PendingWrite[], taskId: string): Promise { - if (!config.configurable?.thread_id) { - throw new Error('config.configurable.thread_id is required'); - } - const dumpedWrites = await this._dumpWrites( - config.configurable?.thread_id, - config.configurable?.checkpoint_ns, - config.configurable?.checkpoint_id, - taskId, - writes, - ); - return await this.sequelize.transaction(async (transaction) => { - const checkpointWrites = await this.checkpointWritesModel.findAll({ - where: { - threadId: config.configurable?.thread_id, - checkpointNs: config.configurable?.checkpoint_ns, - checkpointId: config.configurable?.checkpoint_id, - taskId, - }, - attributes: { - exclude: ['blob'], - }, - transaction, - }); - const duplicateWritesFilter = checkpointWrites.map( - ({ threadId, checkpointNs, checkpointId, taskId, idx }) => - `${threadId}:${checkpointNs}:${checkpointId}:${taskId}:${idx}`, - ); - const dumpedWritesInclude = ([threadId, checkpointNs, checkpointId, taskId, idx]: (typeof dumpedWrites)[0]) => - duplicateWritesFilter.includes(`${threadId}:${checkpointNs}:${checkpointId}:${taskId}:${idx}`); - const dumpedWritesExclude = (item) => !dumpedWritesInclude(item); - - await this.checkpointWritesModel.bulkCreate( - dumpedWrites - .filter(dumpedWritesExclude) - .map(([threadId, checkpointNs, checkpointId, taskId, idx, channel, type, blob]) => ({ - threadId, - checkpointNs, - checkpointId, - taskId, - idx, - channel, - type, - blob: blob ? Buffer.from(blob) : null, - })), - { - transaction, - }, - ); - - for (const [threadId, checkpointNs, checkpointId, taskId, idx, channel, type, blob] of dumpedWrites.filter( - dumpedWritesInclude, - )) { - await this.checkpointWritesModel.update( - { - channel, - type, - blob: blob ? Buffer.from(blob) : null, - }, - { - where: { - threadId, - checkpointNs, - checkpointId, - taskId, - idx, - }, - transaction, - }, - ); - } - }); - } - - deleteThread(threadId: string): Promise { - return this.sequelize.transaction(async (transaction) => { - await this.checkpointsModel.destroy({ - where: { - threadId, - }, - transaction, - }); - await this.checkpointBlobsModel.destroy({ - where: { - threadId, - }, - transaction, - }); - await this.checkpointWritesModel.destroy({ - where: { - threadId, - }, - transaction, - }); - }); - } - - protected async _loadCheckpoint( - checkpoint: Omit, - channelValues: [Uint8Array, Uint8Array, Uint8Array][], - ): Promise { - return { - ...checkpoint, - channel_values: await this._loadBlobs(channelValues), - }; - } - - protected async _loadBlobs(blobValues: [Uint8Array, Uint8Array, Uint8Array][]): Promise> { - if (!blobValues || blobValues.length === 0) { - return {}; - } - const textDecoder = new TextDecoder(); - const entries = await Promise.all( - blobValues - .filter(([, t]) => textDecoder.decode(t) !== 'empty') - .map(async ([k, t, v]) => [textDecoder.decode(k), await this.serde.loadsTyped(textDecoder.decode(t), v)]), - ); - return Object.fromEntries(entries); - } - - protected async _loadMetadata(metadata: Record) { - const [type, dumpedValue] = await this.serde.dumpsTyped(metadata); - return this.serde.loadsTyped(type, dumpedValue); - } - - protected async _loadWrites( - writes: [Uint8Array, Uint8Array, Uint8Array, Uint8Array][], - ): Promise<[string, string, unknown][]> { - const decoder = new TextDecoder(); - return writes - ? await Promise.all( - writes.map(async ([tid, channel, t, v]) => [ - decoder.decode(tid), - decoder.decode(channel), - await this.serde.loadsTyped(decoder.decode(t), v), - ]), - ) - : []; - } - - protected async _dumpBlobs( - threadId: string, - checkpointNs: string, - values: Record, - versions: ChannelVersions, - ): Promise<[string, string, string, string, string, Uint8Array | undefined][]> { - if (Object.keys(versions).length === 0) { - return []; - } - - return Promise.all( - Object.entries(versions).map(async ([k, ver]) => { - const [type, value] = k in values ? await this.serde.dumpsTyped(values[k]) : ['empty', null]; - return [threadId, checkpointNs, k, ver.toString(), type, value ? new Uint8Array(value) : undefined]; - }), - ); - } - - protected _dumpCheckpoint(checkpoint: Checkpoint) { - const serialized: Record = { ...checkpoint }; - if ('channel_values' in serialized) delete serialized.channel_values; - return serialized; - } - - protected async _dumpMetadata(metadata: CheckpointMetadata) { - const [, serializedMetadata] = await this.serde.dumpsTyped(metadata); - // We need to remove null characters before writing - return JSON.parse(new TextDecoder().decode(serializedMetadata).replace(/\0/g, '')); - } - - protected async _dumpWrites( - threadId: string, - checkpointNs: string, - checkpointId: string, - taskId: string, - writes: [string, unknown][], - ): Promise<[string, string, string, string, number, string, string, Uint8Array][]> { - return Promise.all( - writes.map(async ([channel, value], idx) => { - const [type, serializedValue] = await this.serde.dumpsTyped(value); - return [ - threadId, - checkpointNs, - checkpointId, - taskId, - WRITES_IDX_MAP[channel] ?? idx, - channel, - type, - new Uint8Array(serializedValue), - ]; - }), - ); - } - - protected _searchWhere( - config?: RunnableConfig, - filter?: Record, - before?: RunnableConfig, - ): FindOptions { - const findOptions: FindOptions = {}; - - // construct predicate for config filter - if (config?.configurable?.thread_id) { - if (!findOptions.where) { - findOptions.where = {}; - } - findOptions.where['threadId'] = config.configurable.thread_id; - } - - // strict checks for undefined/null because empty strings are falsy - if (config?.configurable?.checkpoint_ns !== undefined && config?.configurable?.checkpoint_ns !== null) { - if (!findOptions.where) { - findOptions.where = {}; - } - findOptions.where['checkpointNs'] = config.configurable.checkpoint_ns; - } - - if (config?.configurable?.checkpoint_id) { - if (!findOptions.where) { - findOptions.where = {}; - } - findOptions.where['checkpointId'] = config.configurable.checkpoint_id; - } - - // construct predicate for metadata filter - if (filter && Object.keys(filter).length > 0) { - if (!findOptions.where) { - findOptions.where = {}; - } - if (this.sequelize.getDialect() === 'postgres') { - findOptions.where['metadata'] = { - [Op.contains]: filter, - }; - } else { - // TODO mysql mariadb sqlite mssql oracle`s metadata filter to be add - } - } - - // construct predicate for `before` - if (before?.configurable?.checkpoint_id !== undefined) { - if (!findOptions.where) { - findOptions.where = {}; - } - findOptions.where['checkpointId'] = { - $lt: before.configurable.checkpoint_id, - }; - } - - return findOptions; - } - - private async getCheckpointWrites( - threadIds: string[], - checkpointNs?: string, - checkpointId?: string, - ): Promise> { - if (!threadIds?.length) { - return {}; - } - const where = { - threadId: - threadIds.length === 1 - ? threadIds[0] - : { - [Op.in]: threadIds, - }, - }; - if (checkpointNs) { - where['checkpointNs'] = checkpointNs; - } - if (checkpointId) { - where['checkpointId'] = checkpointId; - } - const writes = await this.checkpointWritesModel.findAll({ - where, - }); - - const result: Record< - string, - { - taskId: string; - channel: string; - type: string; - blob: Uint8Array; - idx: number; - }[] - > = {}; - for (const write of writes) { - const key = `${write.threadId}:${write.checkpointNs}:${write.checkpointId}`; - if (!result[key]) { - result[key] = []; - } - result[key].push({ - taskId: write.taskId, - channel: write.channel, - type: write.type, - blob: write.blob ? Uint8Array.from(write.blob) : null, - idx: write.idx, - }); - } - return Object.fromEntries( - Object.entries(result).map(([key, list]) => [ - key, - [...list] - .sort((a, b) => { - if (a.taskId !== b.taskId) { - return a.taskId.localeCompare(b.taskId); - } - return a.idx - b.idx; - }) - .map(({ taskId, channel, type, blob }) => [ - new TextEncoder().encode(taskId), - new TextEncoder().encode(channel), - new TextEncoder().encode(type), - blob, - ]), - ]), - ); - } - - private async getPendingSends(threadIds: string[]): Promise> { - if (!threadIds?.length) { - return {}; - } - const writes = await this.checkpointWritesModel.findAll({ - where: { - threadId: { - [Op.in]: threadIds, - }, - channel: TASKS, - }, - }); - - const result: Record< - string, - { - taskId: string; - channel: string; - type: string; - blob: Uint8Array; - idx: number; - }[] - > = {}; - for (const write of writes) { - const key = `${write.threadId}:${write.checkpointId}`; - if (!result[key]) { - result[key] = []; - } - result[key].push({ - taskId: write.taskId, - channel: write.channel, - type: write.type, - blob: write.blob ? Uint8Array.from(write.blob) : null, - idx: write.idx, - }); - } - return Object.fromEntries( - Object.entries(result).map(([key, list]) => [ - key, - [...list] - .sort((a, b) => { - if (a.taskId !== b.taskId) { - return a.taskId.localeCompare(b.taskId); - } - return a.idx - b.idx; - }) - .map(({ type, blob }) => [new TextEncoder().encode(type), blob]), - ]), - ); - } - - private async getCheckpointBlobs( - threadIds: string[], - ): Promise> { - const blobs = await this.checkpointBlobsModel.findAll({ - where: { - threadId: - threadIds.length === 1 - ? threadIds[0] - : { - [Op.in]: threadIds, - }, - }, - }); - const result: Record< - string, - { - taskId: string; - checkpointNs: string; - channel: string; - version: string; - type: string; - blob: Uint8Array; - }[] - > = {}; - for (const blob of blobs) { - const key = `${blob.threadId}:${blob.checkpointNs}:${blob.channel}:${blob.version}`; - if (!result[key]) { - result[key] = []; - } - result[key].push({ - taskId: blob.taskId, - checkpointNs: blob.checkpointNs, - channel: blob.channel, - version: blob.version, - type: blob.type, - blob: blob.blob ? Uint8Array.from(blob.blob) : null, - }); - } - return Object.fromEntries( - Object.entries(result).map(([key, list]) => [ - key, - list.map(({ channel, type, blob }) => [ - new TextEncoder().encode(channel), - new TextEncoder().encode(type), - blob, - ]), - ]), - ); - } - - private get checkpointsModel() { - return this.collectionManager.getCollection('lcCheckpoints').model; - } - - private get checkpointBlobsModel() { - return this.collectionManager.getCollection('lcCheckpointBlobs').model; - } - - private get checkpointWritesModel() { - return this.collectionManager.getCollection('lcCheckpointWrites').model; - } - - private get sequelize() { - return this.collectionManager.db.sequelize; - } - - private get collectionManager() { - return this.provideCollectionManager().collectionManager; - } -} +export { SequelizeCollectionSaver } from './saver'; +export { CheckpointCleaner } from './cleaner'; diff --git a/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/saver.ts b/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/saver.ts new file mode 100644 index 00000000000..2dc5c3559d0 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-ai/src/server/ai-employees/checkpoints/saver.ts @@ -0,0 +1,740 @@ +/** + * This file is part of the NocoBase (R) project. + * Copyright (c) 2020-2024 NocoBase Co., Ltd. + * Authors: NocoBase Team. + * + * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. + * For more information, please refer to: https://www.nocobase.com/agreement. + */ + +import { RunnableConfig } from '@langchain/core/runnables'; +import { + BaseCheckpointSaver, + ChannelVersions, + Checkpoint, + CheckpointListOptions, + CheckpointMetadata, + CheckpointTuple, + maxChannelVersion, + PendingWrite, + SerializerProtocol, + TASKS, + WRITES_IDX_MAP, +} from '@langchain/langgraph-checkpoint'; +import { SequelizeCollectionManager } from '@nocobase/data-source-manager'; +import { FindOptions, Op } from '@nocobase/database'; + +export class SequelizeCollectionSaver extends BaseCheckpointSaver { + constructor( + private readonly provideCollectionManager: () => { collectionManager: SequelizeCollectionManager }, + serde?: SerializerProtocol, + ) { + super(serde); + } + + async getTuple(config: RunnableConfig): Promise { + const { thread_id, checkpoint_ns = '', checkpoint_id } = config.configurable ?? {}; + + let findOptions: FindOptions; + if (checkpoint_id) { + findOptions = { + where: { + threadId: thread_id, + checkpointNs: checkpoint_ns, + checkpointId: checkpoint_id, + }, + }; + } else { + findOptions = { + where: { + threadId: thread_id, + checkpointNs: checkpoint_ns, + }, + order: [['checkpointId', 'DESC']], + limit: 1, + }; + } + + const checkpointRow = (await this.checkpointsModel.findOne(findOptions))?.toJSON(); + if (!checkpointRow) { + return undefined; + } + const { threadId, checkpointNs, checkpointId, parentCheckpointId } = checkpointRow; + + checkpointRow.channelValues = []; + for (const [channel, version] of Object.entries(checkpointRow.checkpoint.channel_versions ?? {})) { + const blob = ( + await this.checkpointBlobsModel.findOne({ + where: { + threadId, + checkpointNs, + channel, + version: String(version), + }, + }) + )?.toJSON(); + if (!blob) { + continue; + } + checkpointRow.channelValues.push([ + new TextEncoder().encode(blob.channel), + new TextEncoder().encode(blob.type), + blob.blob ? Uint8Array.from(blob.blob) : null, + ]); + } + + const checkpointWrites = await this.getCheckpointWrites([threadId], checkpointNs, checkpointId); + checkpointRow.pendingWrites = checkpointWrites[`${threadId}:${checkpointNs}:${checkpointId}`]; + + if (checkpointRow.checkpoint.v < 4 && checkpointRow.parentCheckpointId != null) { + const sendsResult = await this.getPendingSends([threadId]); + const pendingSends = sendsResult[`${threadId}:${parentCheckpointId}`]; + if (pendingSends?.length) { + await this._migratePendingSends(pendingSends, checkpointRow); + } + } + + const checkpoint = await this._loadCheckpoint(checkpointRow.checkpoint, checkpointRow.channelValues); + + const finalConfig = { + configurable: { + thread_id, + checkpoint_ns, + checkpoint_id: checkpointId, + }, + }; + const metadata = await this._loadMetadata(checkpointRow.metadata); + const parentConfig = parentCheckpointId + ? { + configurable: { + thread_id, + checkpoint_ns, + checkpoint_id: parentCheckpointId, + }, + } + : undefined; + + const pendingWrites = await this._loadWrites(checkpointRow.pendingWrites); + + return { + config: finalConfig, + checkpoint, + metadata, + parentConfig, + pendingWrites, + }; + } + + async *list(config: RunnableConfig, options?: CheckpointListOptions): AsyncGenerator { + const { filter, before, limit } = options ?? {}; + const findOptions = this._searchWhere(config, filter, before); + findOptions.order = [['checkpointId', 'DESC']]; + if (limit !== undefined) { + findOptions.limit = Number.parseInt(limit.toString(), 10); // sanitize via parseInt, as limit could be an externally provided value + } + + const result = (await this.checkpointsModel.findAll(findOptions)).map((x) => x.toJSON()); + const [checkpointWrites, checkpointBlobs] = await Promise.all([ + this.getCheckpointWrites(result.map((x) => x.threadId)), + this.getCheckpointBlobs(result.map((x) => x.threadId)), + ]); + + for (const checkpointRow of result) { + const { threadId, checkpointNs, checkpointId } = checkpointRow; + checkpointRow.channelValues = Object.entries(checkpointRow.checkpoint.channel_versions ?? {}) + .map(([channel, version]) => checkpointBlobs[`${threadId}:${checkpointNs}:${channel}:${version}`]) + .filter((x) => x?.length) + .flatMap((x) => [...x]); + checkpointRow.pendingWrites = checkpointWrites[`${threadId}:${checkpointNs}:${checkpointId}`]; + } + const toMigrate = result.filter((row) => row.checkpoint.v < 4 && row.parentCheckpointId != null); + + if (toMigrate.length > 0) { + const sendsResult = await this.getPendingSends(result.map((x) => x.threadId)); + for (const row of toMigrate) { + const pendingSends = sendsResult[`${row.threadId}:${row.parentCheckpointId}`]; + if (pendingSends?.length) { + await this._migratePendingSends(pendingSends, row); + } + } + } + + for (const value of result) { + yield { + config: { + configurable: { + thread_id: value.threadId, + checkpoint_ns: value.checkpointNs, + checkpoint_id: value.checkpointId, + }, + }, + checkpoint: await this._loadCheckpoint(value.checkpoint, value.channelValues), + metadata: await this._loadMetadata(value.metadata), + parentConfig: value.parentCheckpointId + ? { + configurable: { + thread_id: value.threadId, + checkpoint_ns: value.checkpointNs, + checkpoint_id: value.parentCheckpointId, + }, + } + : undefined, + pendingWrites: await this._loadWrites(value.pendingWrites), + }; + } + } + + async _migratePendingSends( + pendingSends: [Uint8Array, Uint8Array][], + mutableRow: { + channelValues: [Uint8Array, Uint8Array, Uint8Array][]; + checkpoint: Omit; + }, + ) { + const textEncoder = new TextEncoder(); + const textDecoder = new TextDecoder(); + const row = mutableRow; + + const [enc, blob] = await this.serde.dumpsTyped( + await Promise.all(pendingSends.map(([enc, blob]) => this.serde.loadsTyped(textDecoder.decode(enc), blob))), + ); + + row.channelValues ??= []; + row.channelValues.push([textEncoder.encode(TASKS), textEncoder.encode(enc), blob]); + + // add to versions + row.checkpoint.channel_versions[TASKS] = + Object.keys(mutableRow.checkpoint.channel_versions).length > 0 + ? maxChannelVersion(...Object.values(mutableRow.checkpoint.channel_versions)) + : this.getNextVersion(undefined); + } + + async put( + config: RunnableConfig, + checkpoint: Checkpoint, + metadata: CheckpointMetadata, + newVersions: ChannelVersions, + ): Promise { + if (config.configurable === undefined) { + throw new Error(`Missing "configurable" field in "config" param`); + } + const { thread_id, checkpoint_ns = '', checkpoint_id } = config.configurable; + + const nextConfig = { + configurable: { + thread_id, + checkpoint_ns, + checkpoint_id: checkpoint.id, + }, + }; + const serializedCheckpoint = this._dumpCheckpoint(checkpoint); + const serializedBlobs = await this._dumpBlobs(thread_id, checkpoint_ns, checkpoint.channel_values, newVersions); + const serializedMetadata = await this._dumpMetadata(metadata); + + return await this.sequelize.transaction(async (transaction) => { + const checkpointBlobs = await this.checkpointBlobsModel.findAll({ + where: { + threadId: thread_id, + checkpointNs: checkpoint_ns, + }, + attributes: { + exclude: ['blob'], + }, + transaction, + }); + const duplicateBlobsFilter = checkpointBlobs.map(({ channel, version }) => `${channel}:${version}`); + + await this.checkpointBlobsModel.bulkCreate( + serializedBlobs + .filter( + ([_threadId, _checkpointNs, channel, version]) => !duplicateBlobsFilter.includes(`${channel}:${version}`), + ) + .map(([threadId, checkpointNs, channel, version, type, blob]) => ({ + threadId, + checkpointNs, + channel, + version, + type, + blob: blob ? Buffer.from(blob) : null, + })), + { + transaction, + }, + ); + + const checkPointFindOptions: FindOptions = { + where: { threadId: thread_id, checkpointNs: checkpoint_ns, checkpointId: checkpoint.id }, + transaction, + }; + const existed = await this.checkpointsModel.count(checkPointFindOptions); + if (existed === 0) { + await this.checkpointsModel.create( + { + threadId: thread_id, + checkpointNs: checkpoint_ns, + checkpointId: checkpoint.id, + parentCheckpointId: checkpoint_id, + checkpoint: serializedCheckpoint, + metadata: serializedMetadata, + }, + { + transaction, + }, + ); + } else { + await this.checkpointsModel.update( + { + checkpoint: serializedCheckpoint, + metadata: serializedMetadata, + }, + { + transaction, + where: checkPointFindOptions.where, + }, + ); + } + + return nextConfig; + }); + } + async putWrites(config: RunnableConfig, writes: PendingWrite[], taskId: string): Promise { + if (!config.configurable?.thread_id) { + throw new Error('config.configurable.thread_id is required'); + } + const dumpedWrites = await this._dumpWrites( + config.configurable?.thread_id, + config.configurable?.checkpoint_ns, + config.configurable?.checkpoint_id, + taskId, + writes, + ); + return await this.sequelize.transaction(async (transaction) => { + const checkpointWrites = await this.checkpointWritesModel.findAll({ + where: { + threadId: config.configurable?.thread_id, + checkpointNs: config.configurable?.checkpoint_ns, + checkpointId: config.configurable?.checkpoint_id, + taskId, + }, + attributes: { + exclude: ['blob'], + }, + transaction, + }); + const duplicateWritesFilter = checkpointWrites.map( + ({ threadId, checkpointNs, checkpointId, taskId, idx }) => + `${threadId}:${checkpointNs}:${checkpointId}:${taskId}:${idx}`, + ); + const dumpedWritesInclude = ([threadId, checkpointNs, checkpointId, taskId, idx]: (typeof dumpedWrites)[0]) => + duplicateWritesFilter.includes(`${threadId}:${checkpointNs}:${checkpointId}:${taskId}:${idx}`); + const dumpedWritesExclude = (item) => !dumpedWritesInclude(item); + + await this.checkpointWritesModel.bulkCreate( + dumpedWrites + .filter(dumpedWritesExclude) + .map(([threadId, checkpointNs, checkpointId, taskId, idx, channel, type, blob]) => ({ + threadId, + checkpointNs, + checkpointId, + taskId, + idx, + channel, + type, + blob: blob ? Buffer.from(blob) : null, + })), + { + transaction, + }, + ); + + for (const [threadId, checkpointNs, checkpointId, taskId, idx, channel, type, blob] of dumpedWrites.filter( + dumpedWritesInclude, + )) { + await this.checkpointWritesModel.update( + { + channel, + type, + blob: blob ? Buffer.from(blob) : null, + }, + { + where: { + threadId, + checkpointNs, + checkpointId, + taskId, + idx, + }, + transaction, + }, + ); + } + }); + } + + deleteThread(threadId: string): Promise { + return this.sequelize.transaction(async (transaction) => { + await this.checkpointsModel.destroy({ + where: { + threadId, + }, + transaction, + }); + await this.checkpointBlobsModel.destroy({ + where: { + threadId, + }, + transaction, + }); + await this.checkpointWritesModel.destroy({ + where: { + threadId, + }, + transaction, + }); + }); + } + + protected async _loadCheckpoint( + checkpoint: Omit, + channelValues: [Uint8Array, Uint8Array, Uint8Array][], + ): Promise { + return { + ...checkpoint, + channel_values: await this._loadBlobs(channelValues), + }; + } + + protected async _loadBlobs(blobValues: [Uint8Array, Uint8Array, Uint8Array][]): Promise> { + if (!blobValues || blobValues.length === 0) { + return {}; + } + const textDecoder = new TextDecoder(); + const entries = await Promise.all( + blobValues + .filter(([, t]) => textDecoder.decode(t) !== 'empty') + .map(async ([k, t, v]) => [textDecoder.decode(k), await this.serde.loadsTyped(textDecoder.decode(t), v)]), + ); + return Object.fromEntries(entries); + } + + protected async _loadMetadata(metadata: Record) { + const [type, dumpedValue] = await this.serde.dumpsTyped(metadata); + return this.serde.loadsTyped(type, dumpedValue); + } + + protected async _loadWrites( + writes: [Uint8Array, Uint8Array, Uint8Array, Uint8Array][], + ): Promise<[string, string, unknown][]> { + const decoder = new TextDecoder(); + return writes + ? await Promise.all( + writes.map(async ([tid, channel, t, v]) => [ + decoder.decode(tid), + decoder.decode(channel), + await this.serde.loadsTyped(decoder.decode(t), v), + ]), + ) + : []; + } + + protected async _dumpBlobs( + threadId: string, + checkpointNs: string, + values: Record, + versions: ChannelVersions, + ): Promise<[string, string, string, string, string, Uint8Array | undefined][]> { + if (Object.keys(versions).length === 0) { + return []; + } + + return Promise.all( + Object.entries(versions).map(async ([k, ver]) => { + const [type, value] = k in values ? await this.serde.dumpsTyped(values[k]) : ['empty', null]; + return [threadId, checkpointNs, k, ver.toString(), type, value ? new Uint8Array(value) : undefined]; + }), + ); + } + + protected _dumpCheckpoint(checkpoint: Checkpoint) { + const serialized: Record = { ...checkpoint }; + if ('channel_values' in serialized) delete serialized.channel_values; + return serialized; + } + + protected async _dumpMetadata(metadata: CheckpointMetadata) { + const [, serializedMetadata] = await this.serde.dumpsTyped(metadata); + // We need to remove null characters before writing + return JSON.parse(new TextDecoder().decode(serializedMetadata).replace(/\0/g, '')); + } + + protected async _dumpWrites( + threadId: string, + checkpointNs: string, + checkpointId: string, + taskId: string, + writes: [string, unknown][], + ): Promise<[string, string, string, string, number, string, string, Uint8Array][]> { + return Promise.all( + writes.map(async ([channel, value], idx) => { + const [type, serializedValue] = await this.serde.dumpsTyped(value); + return [ + threadId, + checkpointNs, + checkpointId, + taskId, + WRITES_IDX_MAP[channel] ?? idx, + channel, + type, + new Uint8Array(serializedValue), + ]; + }), + ); + } + + protected _searchWhere( + config?: RunnableConfig, + filter?: Record, + before?: RunnableConfig, + ): FindOptions { + const findOptions: FindOptions = {}; + + // construct predicate for config filter + if (config?.configurable?.thread_id) { + if (!findOptions.where) { + findOptions.where = {}; + } + findOptions.where['threadId'] = config.configurable.thread_id; + } + + // strict checks for undefined/null because empty strings are falsy + if (config?.configurable?.checkpoint_ns !== undefined && config?.configurable?.checkpoint_ns !== null) { + if (!findOptions.where) { + findOptions.where = {}; + } + findOptions.where['checkpointNs'] = config.configurable.checkpoint_ns; + } + + if (config?.configurable?.checkpoint_id) { + if (!findOptions.where) { + findOptions.where = {}; + } + findOptions.where['checkpointId'] = config.configurable.checkpoint_id; + } + + // construct predicate for metadata filter + if (filter && Object.keys(filter).length > 0) { + if (!findOptions.where) { + findOptions.where = {}; + } + if (this.sequelize.getDialect() === 'postgres') { + findOptions.where['metadata'] = { + [Op.contains]: filter, + }; + } else { + // TODO mysql mariadb sqlite mssql oracle`s metadata filter to be add + } + } + + // construct predicate for `before` + if (before?.configurable?.checkpoint_id !== undefined) { + if (!findOptions.where) { + findOptions.where = {}; + } + findOptions.where['checkpointId'] = { + $lt: before.configurable.checkpoint_id, + }; + } + + return findOptions; + } + + private async getCheckpointWrites( + threadIds: string[], + checkpointNs?: string, + checkpointId?: string, + ): Promise> { + if (!threadIds?.length) { + return {}; + } + const where = { + threadId: + threadIds.length === 1 + ? threadIds[0] + : { + [Op.in]: threadIds, + }, + }; + if (checkpointNs) { + where['checkpointNs'] = checkpointNs; + } + if (checkpointId) { + where['checkpointId'] = checkpointId; + } + const writes = await this.checkpointWritesModel.findAll({ + where, + }); + + const result: Record< + string, + { + taskId: string; + channel: string; + type: string; + blob: Uint8Array; + idx: number; + }[] + > = {}; + for (const write of writes) { + const key = `${write.threadId}:${write.checkpointNs}:${write.checkpointId}`; + if (!result[key]) { + result[key] = []; + } + result[key].push({ + taskId: write.taskId, + channel: write.channel, + type: write.type, + blob: write.blob ? Uint8Array.from(write.blob) : null, + idx: write.idx, + }); + } + return Object.fromEntries( + Object.entries(result).map(([key, list]) => [ + key, + [...list] + .sort((a, b) => { + if (a.taskId !== b.taskId) { + return a.taskId.localeCompare(b.taskId); + } + return a.idx - b.idx; + }) + .map(({ taskId, channel, type, blob }) => [ + new TextEncoder().encode(taskId), + new TextEncoder().encode(channel), + new TextEncoder().encode(type), + blob, + ]), + ]), + ); + } + + private async getPendingSends(threadIds: string[]): Promise> { + if (!threadIds?.length) { + return {}; + } + const writes = await this.checkpointWritesModel.findAll({ + where: { + threadId: { + [Op.in]: threadIds, + }, + channel: TASKS, + }, + }); + + const result: Record< + string, + { + taskId: string; + channel: string; + type: string; + blob: Uint8Array; + idx: number; + }[] + > = {}; + for (const write of writes) { + const key = `${write.threadId}:${write.checkpointId}`; + if (!result[key]) { + result[key] = []; + } + result[key].push({ + taskId: write.taskId, + channel: write.channel, + type: write.type, + blob: write.blob ? Uint8Array.from(write.blob) : null, + idx: write.idx, + }); + } + return Object.fromEntries( + Object.entries(result).map(([key, list]) => [ + key, + [...list] + .sort((a, b) => { + if (a.taskId !== b.taskId) { + return a.taskId.localeCompare(b.taskId); + } + return a.idx - b.idx; + }) + .map(({ type, blob }) => [new TextEncoder().encode(type), blob]), + ]), + ); + } + + private async getCheckpointBlobs( + threadIds: string[], + ): Promise> { + const blobs = await this.checkpointBlobsModel.findAll({ + where: { + threadId: + threadIds.length === 1 + ? threadIds[0] + : { + [Op.in]: threadIds, + }, + }, + }); + const result: Record< + string, + { + taskId: string; + checkpointNs: string; + channel: string; + version: string; + type: string; + blob: Uint8Array; + }[] + > = {}; + for (const blob of blobs) { + const key = `${blob.threadId}:${blob.checkpointNs}:${blob.channel}:${blob.version}`; + if (!result[key]) { + result[key] = []; + } + result[key].push({ + taskId: blob.taskId, + checkpointNs: blob.checkpointNs, + channel: blob.channel, + version: blob.version, + type: blob.type, + blob: blob.blob ? Uint8Array.from(blob.blob) : null, + }); + } + return Object.fromEntries( + Object.entries(result).map(([key, list]) => [ + key, + list.map(({ channel, type, blob }) => [ + new TextEncoder().encode(channel), + new TextEncoder().encode(type), + blob, + ]), + ]), + ); + } + + private get checkpointsModel() { + return this.collectionManager.getCollection('lcCheckpoints').model; + } + + private get checkpointBlobsModel() { + return this.collectionManager.getCollection('lcCheckpointBlobs').model; + } + + private get checkpointWritesModel() { + return this.collectionManager.getCollection('lcCheckpointWrites').model; + } + + private get sequelize() { + return this.collectionManager.db.sequelize; + } + + private get collectionManager() { + return this.provideCollectionManager().collectionManager; + } +} diff --git a/packages/plugins/@nocobase/plugin-ai/src/server/plugin.ts b/packages/plugins/@nocobase/plugin-ai/src/server/plugin.ts index 2acf5c0c197..9598cd7a324 100644 --- a/packages/plugins/@nocobase/plugin-ai/src/server/plugin.ts +++ b/packages/plugins/@nocobase/plugin-ai/src/server/plugin.ts @@ -43,6 +43,7 @@ import { AICodingManager } from './manager/ai-coding-manager'; import { kimiProviderOptions } from './llm-providers/kimi'; import { DocumentLoaders } from './document-loader'; import type PluginFileManagerServer from '@nocobase/plugin-file-manager'; +import { CheckpointCleaner, SequelizeCollectionSaver } from './ai-employees/checkpoints'; // import { tongyiProviderOptions } from './llm-providers/tongyi'; export class PluginAIServer extends Plugin { @@ -74,6 +75,19 @@ export class PluginAIServer extends Plugin { }, }); this.snowflake = new Snowflake(pluginRecord?.createdAt.getTime()); + this.app.cronJobManager.addJob({ + cronTime: '0 0 2 * * *', + onTick: async () => { + try { + const checkpointSaver = new SequelizeCollectionSaver(() => this.app.mainDataSource); + const checkpointCleaner = new CheckpointCleaner(() => this.app.mainDataSource, checkpointSaver); + const expiredAt = new Date(Date.now() - 48 * 60 * 60 * 1000); + await checkpointCleaner.cleanOutdated(expiredAt); + } catch (e) { + this.app.log.error('langChain checkpoint clean job fail', e); + } + }, + }); } async load() { diff --git a/yarn.lock b/yarn.lock index ec1f64341e6..c25e4e08bed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -92,19 +92,6 @@ dependencies: "@alicloud/tea-typescript" "^1.5.1" -"@alicloud/dingtalk@2.2.24": - version "2.2.24" - resolved "https://registry.npmjs.org/@alicloud/dingtalk/-/dingtalk-2.2.24.tgz#df986380bf6a832ef85d02a63c1ba9234e1c67e5" - integrity sha512-OHhYAbIyVhug6bm4pNVElJmZYpgHkvKL6QEkpRFE0geduOUhwB6hY3iLNW2C7RjijUmsWsSvyQRkKWHYgw+8Rg== - dependencies: - "@alicloud/endpoint-util" "^0.0.2" - "@alicloud/gateway-dingtalk" "^1.0.2" - "@alicloud/gateway-spi" "^0.0.8" - "@alicloud/openapi-client" "^0.4.14" - "@alicloud/openapi-util" "^0.3.2" - "@alicloud/tea-typescript" "^1.7.1" - "@alicloud/tea-util" "^1.4.9" - "@alicloud/dysmsapi20170525@2.0.17": version "2.0.17" resolved "https://registry.npmmirror.com/@alicloud/dysmsapi20170525/-/dysmsapi20170525-2.0.17.tgz#a350a443f52456b823772345dd57cc5fe2e6c8da" @@ -124,20 +111,6 @@ "@alicloud/tea-typescript" "^1.5.1" kitx "^2.0.0" -"@alicloud/endpoint-util@^0.0.2": - version "0.0.2" - resolved "https://registry.npmjs.org/@alicloud/endpoint-util/-/endpoint-util-0.0.2.tgz#a86fade1fac4242442e1d19e030f5aa31070d2d3" - integrity sha512-7aqVtcRzM0dVUE7bHLP2wKFuZygx5V6MTHBIbhGH3gfkN3/VZ9LlrxhkEfOCYtWfAyo9q0t9ScxQ4khvhweMqw== - -"@alicloud/gateway-dingtalk@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@alicloud/gateway-dingtalk/-/gateway-dingtalk-1.0.2.tgz#3970f07324c59935892f5b9abce66e6c2ae29dfc" - integrity sha512-T8ml6kth/nCRthrtHIYnCYv7+q/41SnJaR8c99491azNSPcmMmgxis5ujYIl5irKm0cvoOCCjI9EWUFb2Tx7JA== - dependencies: - "@alicloud/gateway-spi" "^0.0.8" - "@alicloud/tea-typescript" "^1.7.1" - "@alicloud/tea-util" "^1.4.5" - "@alicloud/gateway-pop@0.0.6": version "0.0.6" resolved "https://registry.npmjs.org/@alicloud/gateway-pop/-/gateway-pop-0.0.6.tgz#6b84cdbb3b8334f4ad8bca29b736d9c60fcce8cf" @@ -175,7 +148,7 @@ "@alicloud/tea-util" "^1.4.9" "@alicloud/tea-xml" "0.0.3" -"@alicloud/openapi-client@^0.4.14", "@alicloud/openapi-client@^0.4.8", "@alicloud/openapi-client@^0.4.9": +"@alicloud/openapi-client@^0.4.8": version "0.4.15" resolved "https://registry.npmjs.org/@alicloud/openapi-client/-/openapi-client-0.4.15.tgz#fde48ae16af661897883db920a3242e6466447d8" integrity sha512-4VE0/k5ZdQbAhOSTqniVhuX1k5DUeUMZv74degn3wIWjLY6Bq+hxjaGsaHYlLZ2gA5wUrs8NcI5TE+lIQS3iiA== @@ -241,7 +214,7 @@ "@alicloud/tea-typescript" "^1.5.1" kitx "^2.0.0" -"@alicloud/tea-util@^1.4.5", "@alicloud/tea-util@^1.4.8": +"@alicloud/tea-util@^1.4.8": version "1.4.11" resolved "https://registry.npmjs.org/@alicloud/tea-util/-/tea-util-1.4.11.tgz#17fee4f84f41730ba196c27824f8d0d16f9753b5" integrity sha512-HyPEEQ8F0WoZegiCp7sVdrdm6eBOB+GCvGl4182u69LDFktxfirGLcAx3WExUr1zFWkq2OSmBroTwKQ4w/+Yww== @@ -1456,14 +1429,6 @@ "@smithy/util-utf8" "^4.0.0" tslib "^2.6.2" -"@aws-sdk/protocol-http@^3.374.0": - version "3.374.0" - resolved "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.374.0.tgz#e35e76096b995bbed803897a9f4587d11ca34088" - integrity sha512-9WpRUbINdGroV3HiZZIBoJvL2ndoWk39OfwxWs2otxByppJZNN14bg/lvCx5e8ggHUti7IBk5rb0nqQZ4m05pg== - dependencies: - "@smithy/protocol-http" "^1.1.0" - tslib "^2.5.0" - "@aws-sdk/region-config-resolver@3.734.0": version "3.734.0" resolved "https://registry.npmmirror.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.734.0.tgz#45ffbc56a3e94cc5c9e0cd596b0fda60f100f70b" @@ -1476,35 +1441,6 @@ "@smithy/util-middleware" "^4.0.1" tslib "^2.6.2" -"@aws-sdk/s3-presigned-post@3.750.0": - version "3.750.0" - resolved "https://registry.npmjs.org/@aws-sdk/s3-presigned-post/-/s3-presigned-post-3.750.0.tgz#9478be88ed4fe4577090d214784c10345a8c55d3" - integrity sha512-pKCc/ZMj4rSnMwRyRiMfmTIPj5ODc0VM11+Lkywl+rEWru9kH05fww6TYximZuiBcixbaMVkQ4ePXj6DNsRB4w== - dependencies: - "@aws-sdk/client-s3" "3.750.0" - "@aws-sdk/types" "3.734.0" - "@aws-sdk/util-format-url" "3.734.0" - "@smithy/middleware-endpoint" "^4.0.5" - "@smithy/signature-v4" "^5.0.1" - "@smithy/types" "^4.1.0" - "@smithy/util-hex-encoding" "^4.0.0" - "@smithy/util-utf8" "^4.0.0" - tslib "^2.6.2" - -"@aws-sdk/s3-request-presigner@3.750.0": - version "3.750.0" - resolved "https://registry.npmjs.org/@aws-sdk/s3-request-presigner/-/s3-request-presigner-3.750.0.tgz#7c014d6d30a4a8820ad3dcd49a411ad6d637939e" - integrity sha512-G4GNngNQlh9EyJZj2WKOOikX0Fev1WSxTV/XJugaHlpnVriebvi3GzolrgxUpRrcGpFGWjmAxLi/gYxTUla1ow== - dependencies: - "@aws-sdk/signature-v4-multi-region" "3.750.0" - "@aws-sdk/types" "3.734.0" - "@aws-sdk/util-format-url" "3.734.0" - "@smithy/middleware-endpoint" "^4.0.5" - "@smithy/protocol-http" "^5.0.1" - "@smithy/smithy-client" "^4.1.5" - "@smithy/types" "^4.1.0" - tslib "^2.6.2" - "@aws-sdk/signature-v4-multi-region@3.750.0": version "3.750.0" resolved "https://registry.npmmirror.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.750.0.tgz#b948dfc7ab7fbcb97e0df6bdffc03b3f3cecb49a" @@ -1562,16 +1498,6 @@ "@smithy/util-endpoints" "^3.0.1" tslib "^2.6.2" -"@aws-sdk/util-format-url@3.734.0": - version "3.734.0" - resolved "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.734.0.tgz#d78c48d7fc9ff3e15e93d92620bf66b9d1e115fd" - integrity sha512-TxZMVm8V4aR/QkW9/NhujvYpPZjUYqzLwSge5imKZbWFR806NP7RMwc5ilVuHF/bMOln/cVHkl42kATElWBvNw== - dependencies: - "@aws-sdk/types" "3.734.0" - "@smithy/querystring-builder" "^4.0.1" - "@smithy/types" "^4.1.0" - tslib "^2.6.2" - "@aws-sdk/util-locate-window@^3.0.0": version "3.465.0" resolved "https://registry.npmmirror.com/@aws-sdk/util-locate-window/-/util-locate-window-3.465.0.tgz#0471428fb5eb749d4b72c427f5726f7b61fb90eb" @@ -5713,77 +5639,6 @@ dependencies: js-tiktoken "^1.0.12" -"@ldapjs/asn1@2.0.0", "@ldapjs/asn1@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@ldapjs/asn1/-/asn1-2.0.0.tgz#e25fa38fcf0b4310275d6a5a05fe4603efef5eb4" - integrity sha512-G9+DkEOirNgdPmD0I8nu57ygQJKOOgFEMKknEuQvIHbGLwP3ny1mY+OTUYLCbCaGJP4sox5eYgBJRuSUpnAddA== - -"@ldapjs/asn1@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@ldapjs/asn1/-/asn1-1.2.0.tgz#5e99338fb39ff518c205827bec0fd9a6bf6b42db" - integrity sha512-KX/qQJ2xxzvO2/WOvr1UdQ+8P5dVvuOLk/C9b1bIkXxZss8BaR28njXdPgFCpj5aHaf1t8PmuVnea+N9YG9YMw== - -"@ldapjs/attribute@1.0.0", "@ldapjs/attribute@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@ldapjs/attribute/-/attribute-1.0.0.tgz#d81d626080584c1c80ef300a214458f9f78a8abb" - integrity sha512-ptMl2d/5xJ0q+RgmnqOi3Zgwk/TMJYG7dYMC0Keko+yZU6n+oFM59MjQOUht5pxJeS4FWrImhu/LebX24vJNRQ== - dependencies: - "@ldapjs/asn1" "2.0.0" - "@ldapjs/protocol" "^1.2.1" - process-warning "^2.1.0" - -"@ldapjs/change@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@ldapjs/change/-/change-1.0.0.tgz#34818a3a31cb337d3b90ab853bb7fa90517c2c4f" - integrity sha512-EOQNFH1RIku3M1s0OAJOzGfAohuFYXFY4s73wOhRm4KFGhmQQ7MChOh2YtYu9Kwgvuq1B0xKciXVzHCGkB5V+Q== - dependencies: - "@ldapjs/asn1" "2.0.0" - "@ldapjs/attribute" "1.0.0" - -"@ldapjs/controls@^2.1.0": - version "2.1.0" - resolved "https://registry.npmjs.org/@ldapjs/controls/-/controls-2.1.0.tgz#28449cd4352f9389fb52fbf699cfa62f3e8762e6" - integrity sha512-2pFdD1yRC9V9hXfAWvCCO2RRWK9OdIEcJIos/9cCVP9O4k72BY1bLDQQ4KpUoJnl4y/JoD4iFgM+YWT3IfITWw== - dependencies: - "@ldapjs/asn1" "^1.2.0" - "@ldapjs/protocol" "^1.2.1" - -"@ldapjs/dn@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@ldapjs/dn/-/dn-1.1.0.tgz#3687c86d658d2e10aedc2c65a1ef40155dd7370b" - integrity sha512-R72zH5ZeBj/Fujf/yBu78YzpJjJXG46YHFo5E4W1EqfNpo1UsVPqdLrRMXeKIsJT3x9dJVIfR6OpzgINlKpi0A== - dependencies: - "@ldapjs/asn1" "2.0.0" - process-warning "^2.1.0" - -"@ldapjs/filter@^2.1.1": - version "2.1.1" - resolved "https://registry.npmjs.org/@ldapjs/filter/-/filter-2.1.1.tgz#34f4774aa17086ed0186afe11c698f13dd586d56" - integrity sha512-TwPK5eEgNdUO1ABPBUQabcZ+h9heDORE4V9WNZqCtYLKc06+6+UAJ3IAbr0L0bYTnkkWC/JEQD2F+zAFsuikNw== - dependencies: - "@ldapjs/asn1" "2.0.0" - "@ldapjs/protocol" "^1.2.1" - process-warning "^2.1.0" - -"@ldapjs/messages@^1.3.0": - version "1.3.0" - resolved "https://registry.npmjs.org/@ldapjs/messages/-/messages-1.3.0.tgz#dea3c35de6e768e54abd3c7fbaee151d3d01f386" - integrity sha512-K7xZpXJ21bj92jS35wtRbdcNrwmxAtPwy4myeh9duy/eR3xQKvikVycbdWVzkYEAVE5Ce520VXNOwCHjomjCZw== - dependencies: - "@ldapjs/asn1" "^2.0.0" - "@ldapjs/attribute" "^1.0.0" - "@ldapjs/change" "^1.0.0" - "@ldapjs/controls" "^2.1.0" - "@ldapjs/dn" "^1.1.0" - "@ldapjs/filter" "^2.1.1" - "@ldapjs/protocol" "^1.2.1" - process-warning "^2.2.0" - -"@ldapjs/protocol@^1.2.1": - version "1.2.1" - resolved "https://registry.npmjs.org/@ldapjs/protocol/-/protocol-1.2.1.tgz#d58d371d6958f28095e8de23b35341bcaba55cf3" - integrity sha512-O89xFDLW2gBoZWNXuXpBSM32/KealKCTb3JGtJdtUQc7RjAk8XzrRgyz02cPAwGKwKPxy0ivuC7UP9bmN87egQ== - "@lerna/add@4.0.0": version "4.0.0" resolved "https://registry.npmmirror.com/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" @@ -8423,14 +8278,6 @@ "@smithy/types" "^4.1.0" tslib "^2.6.2" -"@smithy/protocol-http@^1.1.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-1.2.0.tgz#a554e4dabb14508f0bc2cdef9c3710e2b294be04" - integrity sha512-GfGfruksi3nXdFok5RhgtOnWe5f6BndzYfmEXISD+5gAGdayFGpjWu5pIqIweTudMtse20bGbc+7MFZXT1Tb8Q== - dependencies: - "@smithy/types" "^1.2.0" - tslib "^2.5.0" - "@smithy/protocol-http@^3.0.11": version "3.0.11" resolved "https://registry.npmmirror.com/@smithy/protocol-http/-/protocol-http-3.0.11.tgz#a9ea712fe7cc3375378ac68d9168a7b6cd0b6f65" @@ -8541,13 +8388,6 @@ "@smithy/util-stream" "^4.1.1" tslib "^2.6.2" -"@smithy/types@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@smithy/types/-/types-1.2.0.tgz#9dc65767b0ee3d6681704fcc67665d6fc9b6a34e" - integrity sha512-z1r00TvBqF3dh4aHhya7nz1HhvCg4TRmw51fjMrh5do3h+ngSstt/yKlNbHeb9QxJmFbmN8KEVSWgb1bRvfEoA== - dependencies: - tslib "^2.5.0" - "@smithy/types@^2.7.0": version "2.7.0" resolved "https://registry.npmmirror.com/@smithy/types/-/types-2.7.0.tgz#6ed9ba5bff7c4d28c980cff967e6d8456840a4f3" @@ -9195,13 +9035,6 @@ resolved "https://registry.npmmirror.com/@types/ali-oss/-/ali-oss-6.23.1.tgz#65a2841a8be69ceb3fbf25654d7d07676632b100" integrity sha512-4mmCq2gUPBaPo6UlLIS/wMc7LxzDCzEUlRJAbLEk68Ntw7KWuF4RUwrQz3gtJkAeIYQ/R6PN3IvPTqk8daVVKQ== -"@types/amqplib@^0.10.7": - version "0.10.8" - resolved "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.10.8.tgz#23f2945d055e9fd583da672aa5ec0c7350b9e4e6" - integrity sha512-vtDp8Pk1wsE/AuQ8/Rgtm6KUZYqcnTgNvEHwzCkX8rL7AGsC6zqAfKAAJhUZXFhM/Pp++tbnUHiam/8vVpPztA== - dependencies: - "@types/node" "*" - "@types/archiver@^5.3.1": version "5.3.4" resolved "https://registry.npmmirror.com/@types/archiver/-/archiver-5.3.4.tgz#32172d5a56f165b5b4ac902e366248bf03d3ae84" @@ -9260,13 +9093,6 @@ "@types/connect" "*" "@types/node" "*" -"@types/carbone@^3.2.5": - version "3.2.5" - resolved "https://registry.npmjs.org/@types/carbone/-/carbone-3.2.5.tgz#3adc4c70a9c5f28e071363cb11bcf44243a4befb" - integrity sha512-qApQQTj87OrULWkMHZVhf370KM2egpV5/W1Xrr0dCDTkVMNJKjD0yw3WlNftel5Co2Pv/E3BvqO8RQzRCtnBTw== - dependencies: - "@types/node" "*" - "@types/connect@*", "@types/connect@3.4.38": version "3.4.38" resolved "https://registry.npmmirror.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" @@ -9833,13 +9659,6 @@ "@types/koa-compose" "*" "@types/node" "*" -"@types/ldapjs@^3.0.6": - version "3.0.6" - resolved "https://registry.npmjs.org/@types/ldapjs/-/ldapjs-3.0.6.tgz#63aec9036c2acfb0e0b7322df336cda2c37f8bbe" - integrity sha512-E2Tn1ltJDYBsidOT9QG4engaQeQzRQ9aYNxVmjCkD33F7cIeLPgrRDXAYs0O35mK2YDU20c/+ZkNjeAPRGLM0Q== - dependencies: - "@types/node" "*" - "@types/lerna__package@*": version "5.1.3" resolved "https://registry.npmmirror.com/@types/lerna__package/-/lerna__package-5.1.3.tgz#3604531e882229dee8e3f2bd8c819c405e2fcb43" @@ -11035,11 +10854,6 @@ loupe "^2.3.7" pretty-format "^29.7.0" -"@wecom/crypto@1.0.1": - version "1.0.1" - resolved "https://registry.npmjs.org/@wecom/crypto/-/crypto-1.0.1.tgz#6918ed9829043b06075eaa8cff84de2475476a58" - integrity sha512-K4Ilkl1l64ceJDbj/kflx8ND/J88pcl8tKx4Ivp7IiCrshRJU+Uo5uWCjAa+PjUiLIdcQSZ4m4d0t1npMPCX5A== - "@xmldom/xmldom@^0.8.10", "@xmldom/xmldom@^0.8.5", "@xmldom/xmldom@^0.8.6", "@xmldom/xmldom@^0.8.8": version "0.8.11" resolved "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz#b79de2d67389734c57c52595f7a7305e30c2d608" @@ -11104,11 +10918,6 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" -abstract-logging@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" - integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== - accepts@^1.3.5, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -11411,14 +11220,6 @@ amp@0.3.1, amp@~0.3.1: resolved "https://registry.npmmirror.com/amp/-/amp-0.3.1.tgz#6adf8d58a74f361e82c1fa8d389c079e139fc47d" integrity sha512-OwIuC4yZaRogHKiuU5WlMR5Xk/jAcpPtawWL05Gj8Lvm2F6mwoJt4O/bHI+DHwG79vWd+8OFYM4/BzYqyRd3qw== -amqplib@^0.10.7: - version "0.10.9" - resolved "https://registry.npmjs.org/amqplib/-/amqplib-0.10.9.tgz#5b744c21d624f9307d0399e4d339b7354675831c" - integrity sha512-jwSftI4QjS3mizvnSnOrPGYiUnm1vI2OP1iXeOUz5pb74Ua0nbf6nPyyTzuiCLEE3fMpaJORXh2K/TQ08H5xGA== - dependencies: - buffer-more-ints "~1.0.0" - url-parse "~1.5.10" - animated-scroll-to@^2.3.0: version "2.3.0" resolved "https://registry.npmmirror.com/animated-scroll-to/-/animated-scroll-to-2.3.0.tgz#01d7a82db7ace7017eae11c5ebbafd3b0270bced" @@ -12387,13 +12188,6 @@ babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" -backoff@^2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" - integrity sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA== - dependencies: - precond "0.2" - bail@^2.0.0: version "2.0.2" resolved "https://registry.npmmirror.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" @@ -12820,11 +12614,6 @@ buffer-indexof-polyfill@~1.0.0: resolved "https://registry.npmmirror.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c" integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A== -buffer-more-ints@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz#ef4f8e2dddbad429ed3828a9c55d44f05c611422" - integrity sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg== - buffer-writer@2.0.0: version "2.0.0" resolved "https://registry.npmmirror.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" @@ -13198,18 +12987,6 @@ capture-stack-trace@^1.0.0: resolved "https://registry.npmmirror.com/capture-stack-trace/-/capture-stack-trace-1.0.2.tgz#1c43f6b059d4249e7f3f8724f15f048b927d3a8a" integrity sha512-X/WM2UQs6VMHUtjUDnZTRI+i1crWteJySFzr9UpGoQa4WQffXVTTXuekjl7TjZRlcF2XfjgITT0HxZ9RnxeT0w== -carbone@^3.5.6: - version "3.5.6" - resolved "https://registry.npmjs.org/carbone/-/carbone-3.5.6.tgz#19ebf24d1f3b337e1c12903e5cf35ff7e3d9e6c8" - integrity sha512-bjTEJAmVQnMJoFAIs6Z0tAUpQoglUH0i4dLV34m8rCKWKagfhAM/zJyyKkU6n9EeyuuoOfCyppsShdvYr0ZfDw== - dependencies: - dayjs "=1.11.11" - dayjs-timezone-iana-plugin "=0.1.0" - debug "=4.3.5" - which "=2.0.2" - yauzl "=2.10.0" - yazl "=2.5.1" - caseless@~0.12.0: version "0.12.0" resolved "https://registry.npmmirror.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -15325,12 +15102,7 @@ dateformat@^3.0.0: resolved "https://registry.npmmirror.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -dayjs-timezone-iana-plugin@=0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/dayjs-timezone-iana-plugin/-/dayjs-timezone-iana-plugin-0.1.0.tgz#216613f6ec80106ab8be025cf5935018c901e997" - integrity sha512-xc8cIZmi4oKr2nfu41I/FDWZKa8n8YaRMxSz9MrpXTNo8c6ZsjZuIoy5RPNmLXPqntFuITWI8obB7lUA+CdzGQ== - -dayjs@1.11.13, dayjs@=1.11.11, dayjs@^1.11.10, dayjs@^1.11.11, dayjs@^1.11.7, dayjs@^1.11.8, dayjs@^1.11.9, dayjs@^1.8.34, dayjs@^1.9.1, dayjs@~1.11.13, dayjs@~1.8.24: +dayjs@1.11.13, dayjs@^1.11.10, dayjs@^1.11.11, dayjs@^1.11.7, dayjs@^1.11.8, dayjs@^1.11.9, dayjs@^1.8.34, dayjs@^1.9.1, dayjs@~1.11.13, dayjs@~1.8.24: version "1.11.13" resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c" integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg== @@ -15375,13 +15147,6 @@ debug@4.3.4: dependencies: ms "2.1.2" -debug@=4.3.5: - version "4.3.5" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== - dependencies: - ms "2.1.2" - debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: version "3.2.7" resolved "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -15843,13 +15608,6 @@ dingbat-to-unicode@^1.0.1: resolved "https://registry.npmjs.org/dingbat-to-unicode/-/dingbat-to-unicode-1.0.1.tgz#5091dd673241453e6b5865e26e5a4452cdef5c83" integrity sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w== -dingtalk-jsapi@3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/dingtalk-jsapi/-/dingtalk-jsapi-3.1.1.tgz#bf0f978aa9f23efc0140845f0f010f3662e1311b" - integrity sha512-Xwt4kv6EZEf5MZWR42yzIHKI95e+Hlqz6X6tcjCiLIyTN8crA87lgs5s3beN7epwCRHcPUyQ7vVm5Q/H3hiUCQ== - dependencies: - promise-polyfill "^7.1.0" - dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -21429,11 +21187,6 @@ joi@^17.13.3: "@sideway/formula" "^3.0.1" "@sideway/pinpoint" "^2.0.0" -jose@^4.15.9: - version "4.15.9" - resolved "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz#9b68eda29e9a0614c042fa29387196c7dd800100" - integrity sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA== - joycon@^3.1.1: version "3.1.1" resolved "https://registry.npmmirror.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" @@ -22112,26 +21865,6 @@ lazystream@^1.0.0: dependencies: readable-stream "^2.0.5" -ldapjs@^3.0.7: - version "3.0.7" - resolved "https://registry.npmjs.org/ldapjs/-/ldapjs-3.0.7.tgz#c69fe2965bc50a747bce834f8183f1f77c3be75d" - integrity sha512-1ky+WrN+4CFMuoekUOv7Y1037XWdjKpu0xAPwSP+9KdvmV9PG+qOKlssDV6a+U32apwxdD3is/BZcWOYzN30cg== - dependencies: - "@ldapjs/asn1" "^2.0.0" - "@ldapjs/attribute" "^1.0.0" - "@ldapjs/change" "^1.0.0" - "@ldapjs/controls" "^2.1.0" - "@ldapjs/dn" "^1.1.0" - "@ldapjs/filter" "^2.1.1" - "@ldapjs/messages" "^1.3.0" - "@ldapjs/protocol" "^1.2.1" - abstract-logging "^2.0.1" - assert-plus "^1.0.0" - backoff "^2.5.0" - once "^1.4.0" - vasync "^2.2.1" - verror "^1.10.1" - leac@^0.6.0: version "0.6.0" resolved "https://registry.npmmirror.com/leac/-/leac-0.6.0.tgz#dcf136e382e666bd2475f44a1096061b70dc0912" @@ -24760,11 +24493,6 @@ nano-memoize@^3.0.16: resolved "https://registry.npmmirror.com/nano-memoize/-/nano-memoize-3.0.16.tgz#454100602713973ac8639bde301e255dd54920ea" integrity sha512-JyK96AKVGAwVeMj3MoMhaSXaUNqgMbCRSQB3trUV8tYZfWEzqUBKdK1qJpfuNXgKeHOx1jv/IEYTM659ly7zUA== -nanoid@3.3.4: - version "3.3.4" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" - integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== - nanoid@^2.1.0: version "2.1.11" resolved "https://registry.npmmirror.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" @@ -25279,11 +25007,6 @@ object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1 resolved "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-hash@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" - integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== - object-hash@^3.0.0: version "3.0.0" resolved "https://registry.npmmirror.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9" @@ -25455,11 +25178,6 @@ officeparser@^5.2.0: pdfjs-dist "^5.3.31" yauzl "^3.1.3" -oidc-token-hash@^5.0.3: - version "5.2.0" - resolved "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.2.0.tgz#be8a8885c7e2478d21a674e15afa31f1bcc4a61f" - integrity sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw== - ollama@^0.6.3: version "0.6.3" resolved "https://registry.npmmirror.com/ollama/-/ollama-0.6.3.tgz#b188573dd0ccb3b4759c1f8fa85067cb17f6673c" @@ -25613,16 +25331,6 @@ opener@^1.5.2: resolved "https://registry.npmmirror.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== -openid-client@^5.4.2: - version "5.7.1" - resolved "https://registry.npmjs.org/openid-client/-/openid-client-5.7.1.tgz#34cace862a3e6472ed7d0a8616ef73b7fb85a9c3" - integrity sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew== - dependencies: - jose "^4.15.9" - lru-cache "^6.0.0" - object-hash "^2.2.0" - oidc-token-hash "^5.0.3" - opt-cli@1.5.1: version "1.5.1" resolved "https://registry.npmmirror.com/opt-cli/-/opt-cli-1.5.1.tgz#04db447b13c96b992eb31685266f4ed0d9736dc2" @@ -27428,11 +27136,6 @@ postgres-interval@^1.1.0: dependencies: xtend "^4.0.0" -precond@0.2: - version "0.2.3" - resolved "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" - integrity sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ== - prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -27576,11 +27279,6 @@ process-warning@^1.0.0: resolved "https://registry.npmmirror.com/process-warning/-/process-warning-1.0.0.tgz#980a0b25dc38cd6034181be4b7726d89066b4616" integrity sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q== -process-warning@^2.1.0, process-warning@^2.2.0: - version "2.3.2" - resolved "https://registry.npmjs.org/process-warning/-/process-warning-2.3.2.tgz#70d8a3251aab0eafe3a595d8ae2c5d2277f096a5" - integrity sha512-n9wh8tvBe5sFmsqlg+XQhaQLumwpqoAUruLwjCopgTmUBjJ/fjtBsJzKleCaIGBOMXYEhp1YfKl4d7rJ5ZKJGA== - process-warning@^3.0.0: version "3.0.0" resolved "https://registry.npmmirror.com/process-warning/-/process-warning-3.0.0.tgz#96e5b88884187a1dce6f5c3166d611132058710b" @@ -27601,11 +27299,6 @@ promise-inflight@^1.0.1: resolved "https://registry.npmmirror.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== -promise-polyfill@^7.1.0: - version "7.1.2" - resolved "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-7.1.2.tgz#ab05301d8c28536301622d69227632269a70ca3b" - integrity sha512-FuEc12/eKqqoRYIGBrUptCBRhobL19PS2U31vMNTfyck1FxPyMfgsXyW4Mav85y/ZN1hop3hOwRlUDok23oYfQ== - promise-retry@^1.1.1: version "1.1.1" resolved "https://registry.npmmirror.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" @@ -27849,7 +27542,7 @@ qs@~6.5.2: resolved "https://registry.npmmirror.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -query-string@6.14.1, query-string@^6.13.6, query-string@^6.13.8, query-string@^6.9.0: +query-string@^6.13.6, query-string@^6.13.8, query-string@^6.9.0: version "6.14.1" resolved "https://registry.npmmirror.com/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" integrity sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw== @@ -27864,11 +27557,6 @@ querystring-es3@^0.2.0: resolved "https://registry.npmmirror.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA== -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -27976,16 +27664,6 @@ raw-body@2.5.2, raw-body@^2.3.3: iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f" - integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.6.3" - unpipe "1.0.0" - raw-body@~2.5.3: version "2.5.3" resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz#11c6650ee770a7de1b494f197927de0c923822e2" @@ -33297,14 +32975,6 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" -url-parse@~1.5.10: - version "1.5.10" - resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" - integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - url-template@^2.0.8: version "2.0.8" resolved "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" @@ -33549,13 +33219,6 @@ vary@^1, vary@^1.1.2, vary@~1.1.2: resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -vasync@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/vasync/-/vasync-2.2.1.tgz#d881379ff3685e4affa8e775cf0fd369262a201b" - integrity sha512-Hq72JaTpcTFdWiNA4Y22Amej2GH3BFmBaKPPlDZ4/oC8HNn2ISHLkFrJU4Ds8R3jcUi7oo5Y9jcMHKjES+N9wQ== - dependencies: - verror "1.10.0" - vditor@^3.10.3: version "3.10.4" resolved "https://registry.npmmirror.com/vditor/-/vditor-3.10.4.tgz#df7e5cdf8c737b588152b2119942ff0e0904c9cd" @@ -33572,15 +33235,6 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -verror@^1.10.1: - version "1.10.1" - resolved "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz#4bf09eeccf4563b109ed4b3d458380c972b0cdeb" - integrity sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg== - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - vfile-location@^4.0.0: version "4.1.0" resolved "https://registry.npmmirror.com/vfile-location/-/vfile-location-4.1.0.tgz#69df82fb9ef0a38d0d02b90dd84620e120050dd0" @@ -33998,13 +33652,6 @@ which-typed-array@^1.1.16, which-typed-array@^1.1.19, which-typed-array@^1.1.2: gopd "^1.2.0" has-tostringtag "^1.0.2" -which@=2.0.2, which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://registry.npmmirror.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - which@^1.2.12, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.npmmirror.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -34012,6 +33659,13 @@ which@^1.2.12, which@^1.2.9, which@^1.3.1: dependencies: isexe "^2.0.0" +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + which@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/which/-/which-4.0.0.tgz#cd60b5e74503a3fbcfbf6cd6b4138a8bae644c1a" @@ -34543,7 +34197,7 @@ yargs@~3.10.0: decamelize "^1.0.0" window-size "0.1.0" -yauzl@=2.10.0, yauzl@^2.10.0, yauzl@^2.4.2: +yauzl@^2.10.0, yauzl@^2.4.2: version "2.10.0" resolved "https://registry.npmmirror.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== @@ -34559,13 +34213,6 @@ yauzl@^3.1.3, yauzl@^3.2.0: buffer-crc32 "~0.2.3" pend "~1.2.0" -yazl@=2.5.1: - version "2.5.1" - resolved "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" - integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== - dependencies: - buffer-crc32 "~0.2.3" - ylru@^1.2.0: version "1.3.2" resolved "https://registry.npmmirror.com/ylru/-/ylru-1.3.2.tgz#0de48017473275a4cbdfc83a1eaf67c01af8a785"