@nocobase/plugin-ai 2.1.0-beta.32 → 2.1.0-beta.34

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.
Files changed (32) hide show
  1. package/dist/ai/docs/nocobase/api/cli/env/remove.md +5 -3
  2. package/dist/ai/docs/nocobase/cluster-mode/index.md +5 -1
  3. package/dist/ai/docs/nocobase/cluster-mode/preparations.md +58 -3
  4. package/dist/externalVersion.js +16 -16
  5. package/dist/node_modules/@langchain/xai/package.json +1 -1
  6. package/dist/node_modules/fs-extra/package.json +1 -1
  7. package/dist/node_modules/jsonrepair/package.json +1 -1
  8. package/dist/node_modules/just-bash/package.json +1 -1
  9. package/dist/node_modules/nodejs-snowflake/package.json +1 -1
  10. package/dist/node_modules/openai/package.json +1 -1
  11. package/dist/node_modules/zod/package.json +1 -1
  12. package/dist/server/ai-employees/ai-employee.d.ts +0 -1
  13. package/dist/server/ai-employees/ai-employee.js +0 -41
  14. package/dist/server/document-loader/cached.d.ts +5 -7
  15. package/dist/server/document-loader/cached.js +49 -120
  16. package/dist/server/document-loader/loader.d.ts +1 -1
  17. package/dist/server/document-loader/loader.js +2 -2
  18. package/dist/server/document-loader/types.d.ts +1 -6
  19. package/dist/server/features/vector-database-provider.d.ts +8 -0
  20. package/dist/server/llm-providers/kimi/document-loader.d.ts +1 -1
  21. package/dist/server/llm-providers/kimi/document-loader.js +4 -4
  22. package/dist/server/llm-providers/provider.d.ts +1 -1
  23. package/dist/server/llm-providers/provider.js +11 -2
  24. package/dist/server/manager/llm-stream-manager.d.ts +16 -10
  25. package/dist/server/manager/llm-stream-manager.js +121 -27
  26. package/dist/server/migrations/20260407170416-ai-employee-knowledge-base-add-key.js +1 -1
  27. package/dist/server/resource/aiConversations.d.ts +12 -13
  28. package/dist/server/resource/aiConversations.js +117 -113
  29. package/dist/server/utils.d.ts +4 -0
  30. package/dist/server/utils.js +9 -0
  31. package/dist/server/workflow/nodes/employee/index.js +3 -4
  32. package/package.json +2 -2
@@ -43,24 +43,21 @@ var import_promises = __toESM(require("node:fs/promises"));
43
43
  var import_node_os = __toESM(require("node:os"));
44
44
  var import_node_path = __toESM(require("node:path"));
45
45
  var import_documents = require("@langchain/core/documents");
46
- var import_constants = require("./constants");
47
46
  var import_utils = require("./utils");
48
47
  class CachedDocumentLoader {
49
48
  constructor(plugin, options) {
50
49
  this.plugin = plugin;
51
50
  this.options = options;
52
51
  }
53
- async load(file) {
52
+ _cache = null;
53
+ async load(file, options) {
54
54
  const sourceFile = this.toPlainObject(file);
55
55
  if (!this.options.supports(sourceFile)) {
56
56
  return {
57
57
  supported: false,
58
58
  fromCache: false,
59
59
  text: "",
60
- documents: [],
61
- meta: {
62
- sourceFileId: sourceFile.id
63
- }
60
+ documents: []
64
61
  };
65
62
  }
66
63
  if (sourceFile.size === 0) {
@@ -68,132 +65,60 @@ class CachedDocumentLoader {
68
65
  supported: true,
69
66
  fromCache: false,
70
67
  text: "",
71
- documents: [],
72
- meta: {
73
- sourceFileId: sourceFile.id
74
- }
68
+ documents: []
75
69
  };
76
70
  }
77
71
  const cached = await this.loadFromCache(sourceFile);
78
72
  if (cached) {
79
73
  return cached;
80
74
  }
81
- try {
82
- const documents = await this.options.loader.load(sourceFile);
83
- const text = this.documentsToText(documents);
84
- const parsedFile = await this.persistParsedText(sourceFile, text);
85
- await this.updateSourceMeta(sourceFile, {
86
- status: "ready",
87
- parserVersion: this.options.parserVersion,
88
- parsedFileId: parsedFile.id,
89
- parsedFilename: parsedFile.filename,
90
- parsedMimetype: this.options.parsedMimetype,
91
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
92
- });
93
- return {
94
- supported: true,
95
- fromCache: false,
96
- text,
97
- documents,
98
- meta: {
99
- sourceFileId: sourceFile.id,
100
- parsedFileId: parsedFile.id
101
- }
102
- };
103
- } catch (error) {
104
- await this.updateSourceMeta(sourceFile, {
105
- status: "failed",
106
- parserVersion: this.options.parserVersion,
107
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
108
- error: (error == null ? void 0 : error.message) ?? String(error)
109
- });
110
- throw error;
111
- }
75
+ const documents = await this.options.loader.load(sourceFile, options);
76
+ const text = this.documentsToText(documents);
77
+ await this.persistParsedText(sourceFile, text);
78
+ return {
79
+ supported: true,
80
+ fromCache: false,
81
+ text,
82
+ documents
83
+ };
112
84
  }
113
85
  async loadFromCache(sourceFile) {
114
- const meta = this.getParseMeta(sourceFile.meta);
115
- if (!meta || meta.status !== "ready" || meta.parserVersion !== this.options.parserVersion || !meta.parsedFileId) {
86
+ const cacheKey = this.getCacheKey(sourceFile);
87
+ if (!cacheKey) {
116
88
  return null;
117
89
  }
118
- const parsedModel = await this.aiFilesRepo.findById(meta.parsedFileId);
119
- if (!parsedModel) {
90
+ const cache = await this.getCache();
91
+ const filePath = await cache.get(cacheKey);
92
+ if (!filePath) {
93
+ return null;
94
+ }
95
+ try {
96
+ const stat = await import_promises.default.stat(filePath);
97
+ if (!stat.isFile()) {
98
+ return null;
99
+ }
100
+ } catch {
120
101
  return null;
121
102
  }
122
- const parsedFile = this.toPlainObject(parsedModel);
123
- const text = await this.readTextFile(parsedFile);
103
+ const text = await import_promises.default.readFile(filePath, "utf-8");
124
104
  const extname = (0, import_utils.resolveExtname)(sourceFile);
125
105
  const documents = this.toDocumentsFromText(text, sourceFile, extname);
126
106
  return {
127
107
  supported: true,
128
108
  fromCache: true,
129
109
  text,
130
- documents,
131
- meta: {
132
- sourceFileId: sourceFile.id,
133
- parsedFileId: parsedFile.id
134
- }
110
+ documents
135
111
  };
136
112
  }
137
113
  async persistParsedText(sourceFile, text) {
138
- const tempFilePath = import_node_path.default.join(
139
- import_node_os.default.tmpdir(),
140
- `${sourceFile.id ?? Date.now()}.${Date.now()}.parsed.${this.options.parsedFileExtname}`
141
- );
142
- await import_promises.default.writeFile(tempFilePath, text, "utf-8");
143
- try {
144
- const storageName = await this.resolveStorageName(sourceFile);
145
- const created = await this.fileManager.createFileRecord({
146
- collectionName: "aiFiles",
147
- filePath: tempFilePath,
148
- storageName,
149
- values: {
150
- title: `${sourceFile.title ?? sourceFile.filename ?? "document"} (parsed)`,
151
- mimetype: this.options.parsedMimetype,
152
- meta: {
153
- parserVersion: this.options.parserVersion,
154
- sourceFileId: sourceFile.id
155
- }
156
- }
157
- });
158
- return this.toPlainObject(created);
159
- } finally {
160
- await import_promises.default.rm(tempFilePath, { force: true });
161
- }
162
- }
163
- async updateSourceMeta(sourceFile, documentParse) {
164
- if (!sourceFile.id) {
165
- return;
166
- }
167
- const nextMeta = {
168
- ...sourceFile.meta ?? {},
169
- [import_constants.DOCUMENT_PARSE_META_KEY]: documentParse
170
- };
171
- await this.aiFilesRepo.update({
172
- filter: {
173
- id: sourceFile.id
174
- },
175
- values: {
176
- meta: nextMeta
177
- }
178
- });
179
- }
180
- async resolveStorageName(file) {
181
- if (!file.storageId) {
182
- return void 0;
183
- }
184
- if (!this.fileManager.storagesCache.size) {
185
- await this.fileManager.loadStorages();
186
- }
187
- const storage = this.fileManager.storagesCache.get(file.storageId);
188
- return storage == null ? void 0 : storage.name;
189
- }
190
- async readTextFile(file) {
191
- const { stream } = await this.fileManager.getFileStream(file);
192
- const chunks = [];
193
- for await (const chunk of stream) {
194
- chunks.push(chunk);
114
+ const cacheKey = this.getCacheKey(sourceFile);
115
+ if (!cacheKey) {
116
+ return null;
195
117
  }
196
- return Buffer.concat(chunks).toString("utf-8");
118
+ const tempFilePath = import_node_path.default.join(import_node_os.default.tmpdir(), `${cacheKey}.${Date.now()}.parsed.${this.options.parsedFileExtname}`);
119
+ await import_promises.default.writeFile(tempFilePath, text, "utf-8");
120
+ const cache = await this.getCache();
121
+ await cache.set(cacheKey, tempFilePath, 30 * 60 * 1e3);
197
122
  }
198
123
  documentsToText(documents) {
199
124
  return documents.map((doc) => doc.pageContent).join("\n\n");
@@ -212,23 +137,27 @@ class CachedDocumentLoader {
212
137
  })
213
138
  ];
214
139
  }
215
- getParseMeta(meta) {
216
- if (!meta || typeof meta !== "object") {
217
- return null;
218
- }
219
- return meta[import_constants.DOCUMENT_PARSE_META_KEY] ?? null;
220
- }
221
140
  toPlainObject(file) {
222
141
  if (file == null ? void 0 : file.toJSON) {
223
142
  return file.toJSON();
224
143
  }
225
144
  return file;
226
145
  }
227
- get aiFilesRepo() {
228
- return this.plugin.db.getRepository("aiFiles");
146
+ async getCache() {
147
+ this._cache ??= await this.plugin.app.cacheManager.createCache({
148
+ name: "ai-employee:document-loader:parsed",
149
+ store: "memory"
150
+ });
151
+ return this._cache;
229
152
  }
230
- get fileManager() {
231
- return this.plugin.app.pm.get("file-manager");
153
+ getCacheKey(sourceFile) {
154
+ if (!sourceFile) {
155
+ return null;
156
+ }
157
+ if (!sourceFile.id || !sourceFile.storageId) {
158
+ return null;
159
+ }
160
+ return `${sourceFile.id}@${sourceFile.storageId}`;
232
161
  }
233
162
  }
234
163
  // Annotate the CommonJS export names for ESM import in node:
@@ -12,6 +12,6 @@ import { ParseableFile } from './types';
12
12
  export declare class DocumentLoader {
13
13
  private readonly fileManager;
14
14
  constructor(fileManager: PluginFileManagerServer);
15
- load(file: ParseableFile): Promise<Document[]>;
15
+ load(file: ParseableFile, options?: any): Promise<Document[]>;
16
16
  private streamToBlob;
17
17
  }
@@ -36,12 +36,12 @@ class DocumentLoader {
36
36
  constructor(fileManager) {
37
37
  this.fileManager = fileManager;
38
38
  }
39
- async load(file) {
39
+ async load(file, options) {
40
40
  const extname = (0, import_utils.resolveExtname)(file);
41
41
  if (!import_constants.SUPPORTED_DOCUMENT_EXTNAMES.includes(extname)) {
42
42
  return [];
43
43
  }
44
- const { stream, contentType } = await this.fileManager.getFileStream(file);
44
+ const { stream, contentType } = await this.fileManager.getFileStream(file, options);
45
45
  const blob = await this.streamToBlob(stream, contentType ?? file.mimetype);
46
46
  return await (0, import_ai.loadByWorker)(extname, blob);
47
47
  }
@@ -21,11 +21,6 @@ export type ParsedDocumentResult = {
21
21
  fromCache: boolean;
22
22
  text: string;
23
23
  documents: Document[];
24
- meta?: {
25
- sourceFileId?: string | number;
26
- parsedFileId?: string | number;
27
- extname?: string;
28
- };
29
24
  };
30
25
  export type ParseableFile = {
31
26
  id?: number | string;
@@ -38,5 +33,5 @@ export type ParseableFile = {
38
33
  size?: number;
39
34
  };
40
35
  export type DocumentLoaderLike = {
41
- load(file: ParseableFile): Promise<Document[]>;
36
+ load(file: ParseableFile, options?: any): Promise<Document[]>;
42
37
  };
@@ -14,6 +14,10 @@ export interface VectorDatabaseProviderFeature {
14
14
  success: boolean;
15
15
  error?: string;
16
16
  }>;
17
+ beforeCreate<T>(providerName: string, connectParams: T, options?: any): Promise<{
18
+ status: number;
19
+ message?: string;
20
+ }>;
17
21
  createVectorStore<T, R>(providerName: string, embeddings: EmbeddingsInterface, connectParams: T): Promise<R>;
18
22
  listProviders(): VectorDatabaseProviderInfo<unknown, unknown>[];
19
23
  }
@@ -28,5 +32,9 @@ export type VectorDatabaseProvider<T, R> = {
28
32
  success: boolean;
29
33
  error?: string;
30
34
  }>;
35
+ beforeCreate(connectParams: T, options?: any): Promise<{
36
+ status: number;
37
+ message?: string;
38
+ }>;
31
39
  createVectorStore(embeddings: EmbeddingsInterface, connectParams: T): Promise<R>;
32
40
  };
@@ -17,7 +17,7 @@ export declare class KimiDocumentLoader {
17
17
  apiKey?: string;
18
18
  baseURL?: string;
19
19
  });
20
- load(file: ParseableFile): Promise<Document[]>;
20
+ load(file: ParseableFile, options?: any): Promise<Document[]>;
21
21
  private parseByApi;
22
22
  private deleteRemoteFile;
23
23
  private formatApiError;
@@ -54,8 +54,8 @@ class KimiDocumentLoader {
54
54
  this.client = this.createClient();
55
55
  }
56
56
  client;
57
- async load(file) {
58
- const text = await this.parseByApi(file);
57
+ async load(file, options) {
58
+ const text = await this.parseByApi(file, options);
59
59
  if (!text) {
60
60
  return [];
61
61
  }
@@ -69,12 +69,12 @@ class KimiDocumentLoader {
69
69
  })
70
70
  ];
71
71
  }
72
- async parseByApi(sourceFile) {
72
+ async parseByApi(sourceFile, options) {
73
73
  let uploadedFileId = "";
74
74
  const safeFilename = import_node_path.default.basename(sourceFile.filename || "document");
75
75
  const tempFilePath = import_node_path.default.join(import_node_os.default.tmpdir(), `${sourceFile.id ?? Date.now()}.${Date.now()}.${safeFilename}`);
76
76
  try {
77
- const { stream } = await this.fileManager.getFileStream(sourceFile);
77
+ const { stream } = await this.fileManager.getFileStream(sourceFile, options);
78
78
  await (0, import_promises2.pipeline)(stream, (0, import_node_fs.createWriteStream)(tempFilePath));
79
79
  let uploaded;
80
80
  try {
@@ -70,7 +70,7 @@ export declare abstract class LLMProvider {
70
70
  protected isApiSupportedAttachment(attachment: AttachmentModel): boolean;
71
71
  protected isDocumentLoaderSupportedAttachment(attachment: AttachmentModel): boolean;
72
72
  protected convertToContent(ctx: Context, attachment: any): Promise<ParsedAttachmentResult>;
73
- protected loadDocument(_ctx: Context, attachment: any): Promise<any>;
73
+ protected loadDocument(ctx: Context, attachment: any): Promise<any>;
74
74
  getStructuredOutputOptions(structuredOutput: AIChatContext['structuredOutput']): any;
75
75
  testFlight(): Promise<{
76
76
  status: 'success' | 'error';
@@ -202,9 +202,18 @@ class LLMProvider {
202
202
  };
203
203
  }
204
204
  }
205
- async loadDocument(_ctx, attachment) {
205
+ async loadDocument(ctx, attachment) {
206
+ const referer = ctx.get("referer") || "";
207
+ const ua = ctx.get("user-agent") || "";
206
208
  const safeFilename = attachment.filename ? import_node_path.default.basename(attachment.filename) : "document";
207
- const parsed = await this.documentLoader.load(attachment);
209
+ const parsed = await this.documentLoader.load(attachment, {
210
+ requestOptions: {
211
+ headers: {
212
+ Referer: referer,
213
+ "User-Agent": ua
214
+ }
215
+ }
216
+ });
208
217
  if (!parsed.supported) {
209
218
  return {
210
219
  placement: "system",
@@ -7,6 +7,11 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
  import PluginAIServer from '../plugin';
10
+ type LLMStreamOptions = {
11
+ pollInterval?: number;
12
+ initialWaitTimeout?: number;
13
+ signal?: AbortSignal;
14
+ };
10
15
  export declare class LLMStreamCachedManager {
11
16
  private readonly plugin;
12
17
  private cachePromise?;
@@ -14,14 +19,10 @@ export declare class LLMStreamCachedManager {
14
19
  getCached(sessionId: string): LLMStreamCached;
15
20
  clear(sessionId: string): Promise<void>;
16
21
  append(sessionId: string, chunk: string): Promise<void>;
17
- stream(sessionId: string, options?: {
18
- pollInterval?: number;
19
- initialWaitTimeout?: number;
20
- }): AsyncGenerator<string, void, void>;
22
+ stream(sessionId: string, options?: LLMStreamOptions): AsyncGenerator<string, void, void>;
21
23
  private getChunks;
22
24
  private getCache;
23
- private withLock;
24
- private getLockKey;
25
+ private get store();
25
26
  }
26
27
  export declare class LLMStreamCached {
27
28
  private readonly sessionId;
@@ -30,8 +31,13 @@ export declare class LLMStreamCached {
30
31
  clear(): Promise<void>;
31
32
  append(chunk: string): Promise<void>;
32
33
  skipped(): Promise<void>;
33
- stream(options?: {
34
- pollInterval?: number;
35
- initialWaitTimeout?: number;
36
- }): AsyncGenerator<string, void, void>;
34
+ stream(options?: LLMStreamOptions): AsyncGenerator<string, void, void>;
37
35
  }
36
+ export declare class BufferedLLMStreamCached extends LLMStreamCached {
37
+ private buffer;
38
+ private interval;
39
+ clear(): Promise<void>;
40
+ append(chunk: string): Promise<void>;
41
+ private flush;
42
+ }
43
+ export {};
@@ -26,54 +26,59 @@ var __copyProps = (to, from, except, desc) => {
26
26
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
27
  var llm_stream_manager_exports = {};
28
28
  __export(llm_stream_manager_exports, {
29
+ BufferedLLMStreamCached: () => BufferedLLMStreamCached,
29
30
  LLMStreamCached: () => LLMStreamCached,
30
31
  LLMStreamCachedManager: () => LLMStreamCachedManager
31
32
  });
32
33
  module.exports = __toCommonJS(llm_stream_manager_exports);
33
- var import_utils = require("@nocobase/utils");
34
34
  const CACHE_NAME = "ai-llm-stream-cache";
35
- const LOCK_KEY_PREFIX = "ai-llm-stream-lock";
36
- const WRITE_LOCK_TTL = 3e3;
37
35
  const CACHE_TTL = 10 * 60 * 1e3;
38
36
  const STREAM_END_MARK = '"type":"stream_end"';
39
37
  const SKIPPED_MARK = "__skipped__";
40
- const DEFAULT_POLL_INTERVAL = 50;
41
- const DEFAULT_INITIAL_WAIT_TIMEOUT = 1e3;
38
+ const DEFAULT_INITIAL_WAIT_TIMEOUT = 1e4;
42
39
  class LLMStreamCachedManager {
43
40
  constructor(plugin) {
44
41
  this.plugin = plugin;
45
42
  }
46
43
  cachePromise;
47
44
  getCached(sessionId) {
45
+ if (this.store !== "memory") {
46
+ return new BufferedLLMStreamCached(sessionId, this);
47
+ }
48
48
  return new LLMStreamCached(sessionId, this);
49
49
  }
50
50
  async clear(sessionId) {
51
- await this.withLock(sessionId, async () => {
52
- const cache = await this.getCache();
53
- await cache.del(sessionId);
54
- });
51
+ const cache = await this.getCache();
52
+ await cache.del(sessionId);
55
53
  }
56
54
  async append(sessionId, chunk) {
57
- await this.withLock(sessionId, async () => {
58
- const cache = await this.getCache();
59
- const chunks = await cache.get(sessionId) ?? [];
60
- chunks.push(chunk);
61
- await cache.set(sessionId, chunks, CACHE_TTL);
62
- });
55
+ const cache = await this.getCache();
56
+ const chunks = await cache.get(sessionId) ?? [];
57
+ chunks.push(chunk);
58
+ await cache.set(sessionId, chunks, CACHE_TTL);
63
59
  }
64
60
  async *stream(sessionId, options) {
65
- const pollInterval = (options == null ? void 0 : options.pollInterval) ?? DEFAULT_POLL_INTERVAL;
61
+ const pollInterval = (options == null ? void 0 : options.pollInterval) ?? (this.store !== "memory" ? 1e3 : 100);
66
62
  const initialWaitTimeout = (options == null ? void 0 : options.initialWaitTimeout) ?? DEFAULT_INITIAL_WAIT_TIMEOUT;
63
+ const signal = options == null ? void 0 : options.signal;
67
64
  let offset = 0;
68
65
  let waited = 0;
69
66
  let completed = false;
70
67
  while (!completed) {
68
+ if (signal == null ? void 0 : signal.aborted) {
69
+ return;
70
+ }
71
71
  const chunks = await this.getChunks(sessionId);
72
72
  const lastSkippedIndex = chunks.lastIndexOf(SKIPPED_MARK);
73
+ let hasNewChunks = false;
73
74
  if (lastSkippedIndex >= offset) {
74
75
  offset = lastSkippedIndex + 1;
75
76
  }
76
77
  while (offset < chunks.length) {
78
+ if (signal == null ? void 0 : signal.aborted) {
79
+ return;
80
+ }
81
+ hasNewChunks = true;
77
82
  const chunk = chunks[offset++];
78
83
  yield chunk;
79
84
  waited = 0;
@@ -85,16 +90,15 @@ class LLMStreamCachedManager {
85
90
  if (completed) {
86
91
  return;
87
92
  }
88
- if (!chunks.length) {
89
- if (offset > 0) {
90
- return;
91
- }
93
+ if (!hasNewChunks) {
92
94
  if (waited >= initialWaitTimeout) {
93
95
  return;
94
96
  }
95
97
  waited += pollInterval;
96
98
  }
97
- await (0, import_utils.sleep)(pollInterval);
99
+ if (await abortableSleep(pollInterval, signal)) {
100
+ return;
101
+ }
98
102
  }
99
103
  }
100
104
  async getChunks(sessionId) {
@@ -104,15 +108,13 @@ class LLMStreamCachedManager {
104
108
  async getCache() {
105
109
  this.cachePromise ??= this.plugin.app.cacheManager.createCache({
106
110
  name: CACHE_NAME,
107
- store: this.plugin.app.cacheManager.defaultStore
111
+ store: this.store
108
112
  });
109
113
  return this.cachePromise;
110
114
  }
111
- async withLock(sessionId, fn) {
112
- return await this.plugin.app.lockManager.runExclusive(this.getLockKey(sessionId), fn, WRITE_LOCK_TTL);
113
- }
114
- getLockKey(sessionId) {
115
- return `${LOCK_KEY_PREFIX}:${sessionId}`;
115
+ get store() {
116
+ var _a;
117
+ return ((_a = this.plugin.app.options.cacheManager) == null ? void 0 : _a.defaultStore) ?? "memory";
116
118
  }
117
119
  }
118
120
  class LLMStreamCached {
@@ -135,8 +137,100 @@ class LLMStreamCached {
135
137
  }
136
138
  }
137
139
  }
140
+ class BufferedLLMStreamCached extends LLMStreamCached {
141
+ buffer = new ChunksBuffer();
142
+ interval;
143
+ async clear() {
144
+ clearInterval(this.interval);
145
+ delete this.interval;
146
+ await this.flush();
147
+ await super.clear();
148
+ }
149
+ async append(chunk) {
150
+ if (!this.interval) {
151
+ this.interval = setInterval(() => {
152
+ void this.flush();
153
+ }, 1e3);
154
+ }
155
+ this.buffer.append(chunk);
156
+ }
157
+ async flush() {
158
+ if (this.buffer.isEmpty()) {
159
+ return;
160
+ }
161
+ const chunks = this.buffer.compact();
162
+ this.buffer.clear();
163
+ const appendChunks = async () => {
164
+ for (const chunk of chunks) {
165
+ await super.append(chunk);
166
+ }
167
+ };
168
+ await appendChunks();
169
+ }
170
+ }
171
+ class ChunksBuffer {
172
+ _size = 0;
173
+ _chunks = [];
174
+ append(chunk) {
175
+ this._size += chunk.length;
176
+ this._chunks.push(chunk);
177
+ }
178
+ clear() {
179
+ this._size = 0;
180
+ this._chunks = [];
181
+ }
182
+ isEmpty() {
183
+ return this._size === 0;
184
+ }
185
+ get size() {
186
+ return this._size;
187
+ }
188
+ get chunks() {
189
+ return this._chunks;
190
+ }
191
+ compact() {
192
+ const chunks = [];
193
+ let buffer = "";
194
+ for (const chunk of this._chunks) {
195
+ if (chunk === SKIPPED_MARK) {
196
+ if (buffer) {
197
+ chunks.push(buffer);
198
+ buffer = "";
199
+ }
200
+ chunks.push(SKIPPED_MARK);
201
+ } else {
202
+ buffer += chunk;
203
+ }
204
+ }
205
+ if (buffer) {
206
+ chunks.push(buffer);
207
+ }
208
+ return chunks;
209
+ }
210
+ }
211
+ function abortableSleep(ms, signal) {
212
+ if (signal == null ? void 0 : signal.aborted) {
213
+ return Promise.resolve(true);
214
+ }
215
+ return new Promise((resolve) => {
216
+ const timeout = setTimeout(() => {
217
+ cleanup();
218
+ resolve(false);
219
+ }, ms);
220
+ const cleanup = () => {
221
+ clearTimeout(timeout);
222
+ signal == null ? void 0 : signal.removeEventListener("abort", abort);
223
+ };
224
+ const abort = () => {
225
+ cleanup();
226
+ resolve(true);
227
+ };
228
+ signal == null ? void 0 : signal.addEventListener("abort", abort, { once: true });
229
+ });
230
+ }
138
231
  // Annotate the CommonJS export names for ESM import in node:
139
232
  0 && (module.exports = {
233
+ BufferedLLMStreamCached,
140
234
  LLMStreamCached,
141
235
  LLMStreamCachedManager
142
236
  });
@@ -33,7 +33,7 @@ var import_server = require("@nocobase/server");
33
33
  class ai_employee_knowledge_base_add_key_default extends import_server.Migration {
34
34
  on = "afterSync";
35
35
  // 'beforeLoad' or 'afterLoad'
36
- appVersion = "<2.1.0";
36
+ appVersion = "<2.2.0";
37
37
  async up() {
38
38
  var _a, _b, _c, _d;
39
39
  const aiEmployeesRepo = this.app.db.getRepository("aiEmployees");
@@ -7,28 +7,27 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
  import { Context, Next } from '@nocobase/actions';
10
- declare function parallelConversationsLimit(ctx: Context, next: Next): Promise<never>;
10
+ declare function loginInCheck(ctx: Context, next: Next): Promise<never>;
11
11
  declare const _default: {
12
12
  name: string;
13
13
  middlewares: {
14
- only: string[];
15
- handler: typeof parallelConversationsLimit;
14
+ handler: typeof loginInCheck;
16
15
  }[];
17
16
  actions: {
18
17
  list(ctx: Context, next: Next): Promise<void>;
19
- unreadCount(ctx: Context, next: Next): Promise<never>;
20
- unreadCounts(ctx: Context, next: Next): Promise<never>;
21
- create(ctx: Context, next: Next): Promise<never>;
22
- update(ctx: Context, next: Next): Promise<never>;
18
+ unreadCount(ctx: Context, next: Next): Promise<void>;
19
+ unreadCounts(ctx: Context, next: Next): Promise<void>;
20
+ create(ctx: Context, next: Next): Promise<void>;
21
+ update(ctx: Context, next: Next): Promise<void>;
23
22
  updateOptions(ctx: Context, next: Next): Promise<never>;
24
23
  destroy(ctx: Context, next: Next): Promise<void>;
25
- getMessages(ctx: Context, next: Next): Promise<never>;
24
+ getMessages(ctx: Context, next: Next): Promise<void>;
26
25
  updateToolArgs(ctx: Context, next: Next): Promise<any>;
27
- sendMessages(ctx: Context, next: Next): Promise<any>;
28
- abort(ctx: Context, next: Next): Promise<never>;
29
- resumeStream(ctx: Context, next: Next): Promise<never>;
30
- resendMessages(ctx: Context, next: Next): Promise<any>;
31
- updateUserDecision(ctx: Context, next: Next): Promise<never>;
26
+ sendMessages(ctx: Context, next: Next): Promise<void>;
27
+ abort(ctx: Context, next: Next): Promise<void>;
28
+ resumeStream(ctx: Context, next: Next): Promise<void>;
29
+ resendMessages(ctx: Context, next: Next): Promise<void>;
30
+ updateUserDecision(ctx: Context, next: Next): Promise<void>;
32
31
  resumeToolCall(ctx: Context, next: Next): Promise<any>;
33
32
  };
34
33
  };