@nocobase/plugin-ai 2.1.0-alpha.33 → 2.1.0-alpha.35

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 (132) hide show
  1. package/client-v2.d.ts +1 -0
  2. package/client-v2.js +1 -0
  3. package/dist/ai/docs/nocobase/ai/index.md +1 -1
  4. package/dist/ai/docs/nocobase/ai-employees/built-in/atlas.md +24 -0
  5. package/dist/ai/docs/nocobase/ai-employees/built-in/dara.md +22 -0
  6. package/dist/ai/docs/nocobase/ai-employees/built-in/dex.md +32 -0
  7. package/dist/ai/docs/nocobase/ai-employees/built-in/ellis.md +22 -0
  8. package/dist/ai/docs/nocobase/ai-employees/built-in/index.md +25 -0
  9. package/dist/ai/docs/nocobase/ai-employees/built-in/lexi.md +26 -0
  10. package/dist/ai/docs/nocobase/ai-employees/built-in/lina.md +142 -0
  11. package/dist/ai/docs/nocobase/ai-employees/built-in/nathan.md +36 -0
  12. package/dist/ai/docs/nocobase/ai-employees/built-in/vera.md +22 -0
  13. package/dist/ai/docs/nocobase/ai-employees/built-in/viz.md +25 -0
  14. package/dist/ai/docs/nocobase/ai-employees/features/built-in-employee.md +1 -29
  15. package/dist/ai/docs/nocobase/ai-employees/features/collaborate.md +17 -7
  16. package/dist/ai/docs/nocobase/ai-employees/features/enable-ai-employee.md +4 -4
  17. package/dist/ai/docs/nocobase/ai-employees/features/model-settings.md +87 -0
  18. package/dist/ai/docs/nocobase/ai-employees/index.md +1 -1
  19. package/dist/ai/docs/nocobase/ai-employees/scenarios/localization-hy-mt.md +241 -0
  20. package/dist/ai/docs/nocobase/ai-employees/workflow/nodes/employee/configuration.md +1 -1
  21. package/dist/ai/docs/nocobase/cluster-mode/index.md +5 -1
  22. package/dist/ai/docs/nocobase/cluster-mode/preparations.md +58 -3
  23. package/dist/ai/docs/nocobase/get-started/deployment/how-to-deploy-nocobase-faster.mdx +384 -0
  24. package/dist/ai/docs/nocobase/get-started/upgrading/docker.md +1 -1
  25. package/dist/ai/docs/nocobase/interface-builder/actions/types/js-action.md +1 -1
  26. package/dist/ai/docs/nocobase/interface-builder/actions/types/js-item.md +1 -1
  27. package/dist/ai/docs/nocobase/interface-builder/blocks/other-blocks/js-block.md +1 -1
  28. package/dist/ai/docs/nocobase/interface-builder/fields/specific/js-column.md +1 -1
  29. package/dist/ai/docs/nocobase/interface-builder/fields/specific/js-field.md +1 -1
  30. package/dist/ai/docs/nocobase/interface-builder/fields/specific/js-item.md +1 -1
  31. package/dist/ai/docs/nocobase/security/guide.md +13 -1
  32. package/dist/ai/docs/nocobase/system-management/localization/index.md +25 -1
  33. package/dist/client/119.c6bf8c6433167d81.js +10 -0
  34. package/dist/client/228.b4b709f93b86b6b9.js +10 -0
  35. package/dist/client/462.1708385b148779cd.js +10 -0
  36. package/dist/client/{486.afbed6b132b3c0dd.js → 486.dcac8f3fcec19c33.js} +1 -1
  37. package/dist/client/{559.39872901b9053629.js → 559.585f80c3bcea0bed.js} +1 -1
  38. package/dist/client/597.b0d64948d74cf6cb.js +10 -0
  39. package/dist/client/646.b0ed728921b007d4.js +10 -0
  40. package/dist/client/711.92cd94681fde7e05.js +10 -0
  41. package/dist/client/768.5177bff46ae71a5b.js +10 -0
  42. package/dist/client/792.abb57765453bcbcc.js +10 -0
  43. package/dist/client/820.f72ef2462b61d812.js +10 -0
  44. package/dist/client/927.d95c74ebb8fd51c9.js +10 -0
  45. package/dist/client/ai-employees/admin/ModelSettings.d.ts +10 -0
  46. package/dist/client/ai-employees/admin/hooks.d.ts +1 -1
  47. package/dist/client/ai-employees/avatars.d.ts +9 -783
  48. package/dist/client/ai-employees/chatbox/conversations/ConversationsList.d.ts +1 -15
  49. package/dist/client/ai-employees/chatbox/conversations/WorkflowTasksList.d.ts +1 -21
  50. package/dist/client/ai-employees/chatbox/hooks/useChat.d.ts +125 -0
  51. package/dist/client/ai-employees/chatbox/hooks/useChatBoxActions.d.ts +1 -1
  52. package/dist/client/ai-employees/chatbox/hooks/useChatConversationActions.d.ts +13 -1
  53. package/dist/client/ai-employees/chatbox/hooks/useChatMessageActions.d.ts +8 -8
  54. package/dist/client/ai-employees/chatbox/model.d.ts +6 -3
  55. package/dist/client/ai-employees/chatbox/stores/chat-conversations.d.ts +4 -0
  56. package/dist/client/ai-employees/chatbox/stores/chat-messages.d.ts +77 -50
  57. package/dist/client/ai-employees/chatbox/stores/chat-tool-call.d.ts +24 -16
  58. package/dist/client/ai-employees/types.d.ts +24 -0
  59. package/dist/client/features/vector-database-provider.d.ts +1 -1
  60. package/dist/client/index.d.ts +2 -0
  61. package/dist/client/index.js +3 -3
  62. package/dist/client/llm-services/component/EnabledModelsSelect.d.ts +1 -14
  63. package/dist/client-v2/ai-employees/AIEmployeeShortcut.d.ts +21 -0
  64. package/dist/client-v2/ai-employees/ProfileCard.d.ts +17 -0
  65. package/dist/client-v2/ai-employees/avatars.d.ts +783 -0
  66. package/dist/client-v2/ai-employees/types.d.ts +20 -0
  67. package/dist/client-v2/index.d.ts +17 -0
  68. package/dist/client-v2/index.js +10 -0
  69. package/dist/client-v2/llm-services/model-label.d.ts +22 -0
  70. package/dist/collections/ai-employees.d.ts +2 -1
  71. package/dist/collections/ai-employees.js +1 -1
  72. package/dist/externalVersion.js +17 -16
  73. package/dist/locale/en-US.json +16 -1
  74. package/dist/locale/zh-CN.json +16 -1
  75. package/dist/node_modules/@langchain/xai/package.json +1 -1
  76. package/dist/node_modules/fs-extra/package.json +1 -1
  77. package/dist/node_modules/jsonrepair/package.json +1 -1
  78. package/dist/node_modules/just-bash/package.json +1 -1
  79. package/dist/node_modules/nodejs-snowflake/package.json +1 -1
  80. package/dist/node_modules/openai/package.json +1 -1
  81. package/dist/node_modules/zod/package.json +1 -1
  82. package/dist/server/ai-employees/ai-conversations.d.ts +4 -1
  83. package/dist/server/ai-employees/ai-conversations.js +44 -4
  84. package/dist/server/ai-employees/ai-employee.d.ts +31 -15
  85. package/dist/server/ai-employees/ai-employee.js +205 -52
  86. package/dist/server/ai-employees/ai-employees-manager.d.ts +4 -0
  87. package/dist/server/ai-employees/ai-employees-manager.js +41 -0
  88. package/dist/server/ai-employees/ai-knowledge-base.js +7 -7
  89. package/dist/server/ai-employees/middleware/conversation.d.ts +1 -0
  90. package/dist/server/ai-employees/middleware/conversation.js +15 -11
  91. package/dist/server/ai-employees/sub-agents/dispatcher.js +2 -4
  92. package/dist/server/ai-employees/utils.d.ts +6 -3
  93. package/dist/server/ai-employees/utils.js +7 -1
  94. package/dist/server/collections/ai-conversations.js +6 -0
  95. package/dist/server/features/knowledge-base.d.ts +3 -2
  96. package/dist/server/index.d.ts +2 -0
  97. package/dist/server/index.js +3 -0
  98. package/dist/server/llm-providers/common/reasoning.d.ts +2 -0
  99. package/dist/server/llm-providers/common/reasoning.js +15 -2
  100. package/dist/server/llm-providers/dashscope.d.ts +2 -1
  101. package/dist/server/llm-providers/dashscope.js +39 -0
  102. package/dist/server/llm-providers/deepseek.js +2 -0
  103. package/dist/server/llm-providers/provider.d.ts +15 -1
  104. package/dist/server/llm-providers/provider.js +21 -2
  105. package/dist/server/manager/ai-chat-conversation.js +3 -4
  106. package/dist/server/manager/ai-manager.d.ts +17 -0
  107. package/dist/server/manager/ai-manager.js +65 -0
  108. package/dist/server/manager/llm-stream-manager.d.ts +43 -0
  109. package/dist/server/manager/llm-stream-manager.js +236 -0
  110. package/dist/server/migrations/20260407170416-ai-employee-knowledge-base-add-key.d.ts +14 -0
  111. package/dist/server/migrations/20260407170416-ai-employee-knowledge-base-add-key.js +61 -0
  112. package/dist/server/plugin.d.ts +2 -0
  113. package/dist/server/plugin.js +3 -0
  114. package/dist/server/resource/ai.js +1 -41
  115. package/dist/server/resource/aiConversations.d.ts +14 -7
  116. package/dist/server/resource/aiConversations.js +236 -101
  117. package/dist/server/resource/aiEmployees.js +32 -1
  118. package/dist/server/types/knowledge-base.type.d.ts +3 -2
  119. package/dist/server/utils.d.ts +4 -0
  120. package/dist/server/utils.js +9 -0
  121. package/dist/server/workflow/nodes/employee/index.js +4 -2
  122. package/package.json +2 -2
  123. package/dist/client/119.78774f3ad953af49.js +0 -10
  124. package/dist/client/228.a3df2921c8beb766.js +0 -10
  125. package/dist/client/343.6f36d97dd122c5b6.js +0 -10
  126. package/dist/client/597.aa363881a325b5c0.js +0 -10
  127. package/dist/client/646.217a40387efbd163.js +0 -10
  128. package/dist/client/711.266b8f1c520d467a.js +0 -10
  129. package/dist/client/768.973ce32e15099a48.js +0 -10
  130. package/dist/client/792.2e48eab4767d662a.js +0 -10
  131. package/dist/client/820.6a26239ea96c075a.js +0 -10
  132. package/dist/client/927.ff5cd05b14901ae6.js +0 -10
@@ -40,8 +40,10 @@ __export(aiConversations_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(aiConversations_exports);
42
42
  var import_actions = __toESM(require("@nocobase/actions"));
43
+ var import_database = require("@nocobase/database");
43
44
  var import_utils = require("../utils");
44
45
  var import_ai_employee = require("../ai-employees/ai-employee");
46
+ var import_ai_chat_conversation = require("../manager/ai-chat-conversation");
45
47
  async function getAIEmployee(ctx, username) {
46
48
  var _a;
47
49
  const filter = {
@@ -66,15 +68,52 @@ function setupSSEHeaders(ctx) {
66
68
  function sendErrorResponse(ctx, errorMessage) {
67
69
  (0, import_utils.sendSSEError)(ctx, errorMessage);
68
70
  }
71
+ async function loginInCheck(ctx, next) {
72
+ var _a;
73
+ const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
74
+ if (!userId) {
75
+ return ctx.throw(403);
76
+ }
77
+ await next();
78
+ }
79
+ const isReachParallelLimit = async (ctx) => {
80
+ var _a;
81
+ const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
82
+ const activeStreamCount = await ctx.db.getModel("aiConversations").count({
83
+ where: {
84
+ userId,
85
+ llmActiveState: "streaming",
86
+ updatedAt: {
87
+ [import_database.Op.gte]: new Date(Date.now() - 10 * 60 * 1e3)
88
+ }
89
+ }
90
+ });
91
+ return activeStreamCount > 2;
92
+ };
93
+ const saveUserMessages = async (ctx, sessionId, messages, messageId) => {
94
+ const userMessages = messages.filter((message) => message.role === "user");
95
+ if (!userMessages.length) {
96
+ return;
97
+ }
98
+ const aiChatConversation = (0, import_ai_chat_conversation.createAIChatConversation)(ctx, sessionId);
99
+ await aiChatConversation.withTransaction(async (conversation) => {
100
+ if (messageId && await conversation.getMessage(messageId)) {
101
+ await conversation.removeMessages({ messageId });
102
+ }
103
+ await conversation.addMessages(userMessages);
104
+ });
105
+ };
69
106
  var aiConversations_default = {
70
107
  name: "aiConversations",
108
+ middlewares: [
109
+ {
110
+ handler: loginInCheck
111
+ }
112
+ ],
71
113
  actions: {
72
114
  async list(ctx, next) {
73
115
  var _a;
74
116
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
75
- if (!userId) {
76
- return ctx.throw(403);
77
- }
78
117
  const filter = ctx.action.params.filter || {};
79
118
  ctx.action.mergeParams({
80
119
  filter: {
@@ -86,14 +125,52 @@ var aiConversations_default = {
86
125
  });
87
126
  return import_actions.default.list(ctx, next);
88
127
  },
128
+ async unreadCount(ctx, next) {
129
+ var _a;
130
+ const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
131
+ const count = await ctx.db.getModel("aiConversations").count({
132
+ where: {
133
+ userId,
134
+ read: false,
135
+ from: "main-agent",
136
+ category: "chat"
137
+ }
138
+ });
139
+ ctx.body = {
140
+ count
141
+ };
142
+ await next();
143
+ },
144
+ async unreadCounts(ctx, next) {
145
+ var _a;
146
+ const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
147
+ const [conversationUnreadCount, workflowTaskUnreadCount] = await Promise.all([
148
+ ctx.db.getModel("aiConversations").count({
149
+ where: {
150
+ userId,
151
+ read: false,
152
+ from: "main-agent",
153
+ category: "chat"
154
+ }
155
+ }),
156
+ ctx.db.getModel("usersAiWorkflowTasks").count({
157
+ where: {
158
+ userId,
159
+ read: false
160
+ }
161
+ })
162
+ ]);
163
+ ctx.body = {
164
+ conversationUnreadCount,
165
+ workflowTaskUnreadCount
166
+ };
167
+ await next();
168
+ },
89
169
  async create(ctx, next) {
90
170
  var _a;
91
171
  const plugin = ctx.app.pm.get("ai");
92
172
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
93
- if (!userId) {
94
- return ctx.throw(403);
95
- }
96
- const { aiEmployee, systemMessage, skillSettings, conversationSettings } = ctx.action.params.values || {};
173
+ const { aiEmployee, systemMessage, skillSettings, conversationSettings, modelSettings } = ctx.action.params.values || {};
97
174
  const employee = await getAIEmployee(ctx, aiEmployee.username);
98
175
  if (!employee) {
99
176
  ctx.throw(400, "AI employee not found");
@@ -105,7 +182,8 @@ var aiConversations_default = {
105
182
  options: {
106
183
  systemMessage,
107
184
  skillSettings,
108
- conversationSettings
185
+ conversationSettings,
186
+ modelSettings
109
187
  }
110
188
  });
111
189
  } catch (error) {
@@ -120,9 +198,6 @@ var aiConversations_default = {
120
198
  var _a;
121
199
  const plugin = ctx.app.pm.get("ai");
122
200
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
123
- if (!userId) {
124
- return ctx.throw(403);
125
- }
126
201
  const { filterByTk: sessionId } = ctx.action.params;
127
202
  const { title } = ctx.action.params.values || {};
128
203
  ctx.body = await plugin.aiConversationsManager.update({ userId, sessionId, title });
@@ -132,22 +207,19 @@ var aiConversations_default = {
132
207
  var _a;
133
208
  const plugin = ctx.app.pm.get("ai");
134
209
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
135
- if (!userId) {
136
- return ctx.throw(403);
137
- }
138
210
  const { filterByTk: sessionId } = ctx.action.params;
139
211
  if (!sessionId) {
140
212
  return ctx.throw(400, "invalid sessionId");
141
213
  }
142
- const { systemMessage, skillSettings, conversationSettings } = ctx.action.params.values || {};
143
- if (!systemMessage && !skillSettings && !conversationSettings) {
214
+ const { systemMessage, skillSettings, conversationSettings, modelSettings } = ctx.action.params.values || {};
215
+ if (!systemMessage && !skillSettings && !conversationSettings && !modelSettings) {
144
216
  return ctx.throw(400, "invalid options");
145
217
  }
146
218
  try {
147
219
  ctx.body = await plugin.aiConversationsManager.update({
148
220
  userId,
149
221
  sessionId,
150
- options: { systemMessage, skillSettings, conversationSettings }
222
+ options: { systemMessage, skillSettings, conversationSettings, modelSettings }
151
223
  });
152
224
  } catch (error) {
153
225
  if (error.message === "invalid sessionId") {
@@ -160,9 +232,6 @@ var aiConversations_default = {
160
232
  async destroy(ctx, next) {
161
233
  var _a;
162
234
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
163
- if (!userId) {
164
- return ctx.throw(403);
165
- }
166
235
  ctx.action.mergeParams({
167
236
  filter: {
168
237
  userId
@@ -174,20 +243,19 @@ var aiConversations_default = {
174
243
  var _a, _b;
175
244
  const plugin = ctx.app.pm.get("ai");
176
245
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
177
- if (!userId) {
178
- return ctx.throw(403);
179
- }
180
- const { sessionId, cursor } = ctx.action.params || {};
246
+ const { sessionId, cursor, updateRead: originalUpdateRead } = ctx.action.params || {};
181
247
  if (!sessionId) {
182
248
  ctx.throw(400);
183
249
  }
184
250
  const paginate = ((_b = ctx.action.params) == null ? void 0 : _b.paginate) === "false" ? false : true;
251
+ const updateRead = originalUpdateRead === "true" || originalUpdateRead === true;
185
252
  try {
186
253
  ctx.body = await plugin.aiConversationsManager.getMessages({
187
254
  userId,
188
255
  sessionId,
189
256
  cursor,
190
- paginate
257
+ paginate,
258
+ updateRead
191
259
  });
192
260
  } catch (error) {
193
261
  if (error.message === "invalid sessionId") {
@@ -201,9 +269,6 @@ var aiConversations_default = {
201
269
  var _a;
202
270
  const plugin = ctx.app.pm.get("ai");
203
271
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
204
- if (!userId) {
205
- return ctx.throw(403);
206
- }
207
272
  const {
208
273
  sessionId,
209
274
  messageId,
@@ -242,11 +307,8 @@ var aiConversations_default = {
242
307
  },
243
308
  async sendMessages(ctx, next) {
244
309
  var _a, _b, _c, _d;
245
- const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
246
- if (!userId) {
247
- return ctx.throw(403);
248
- }
249
310
  const plugin = ctx.app.pm.get("ai");
311
+ const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
250
312
  const {
251
313
  sessionId,
252
314
  aiEmployee: employeeName,
@@ -260,38 +322,27 @@ var aiConversations_default = {
260
322
  if (shouldStream) {
261
323
  setupSSEHeaders(ctx);
262
324
  }
263
- if (!sessionId) {
264
- if (shouldStream) {
265
- sendErrorResponse(ctx, "sessionId is required");
266
- } else {
267
- ctx.status = 400;
268
- ctx.body = { error: "sessionId is required" };
325
+ try {
326
+ if (!sessionId) {
327
+ throw new import_utils.ResourceActionError(400, ctx.t("sessionId is required"));
269
328
  }
270
- return next();
271
- }
272
- const userMessage = messages.find((message) => message.role === "user");
273
- if (!userMessage) {
274
- if (shouldStream) {
275
- sendErrorResponse(ctx, "user message is required");
276
- } else {
277
- ctx.status = 400;
278
- ctx.body = { error: "user message is required" };
329
+ if (!Array.isArray(messages)) {
330
+ throw new import_utils.ResourceActionError(400, ctx.t("messages must be an array"));
331
+ }
332
+ const userMessage = messages.find((message) => message.role === "user");
333
+ if (!userMessage) {
334
+ throw new import_utils.ResourceActionError(400, ctx.t("user message is required"));
279
335
  }
280
- return next();
281
- }
282
- try {
283
336
  const conversation = await plugin.aiConversationsManager.getConversation({
284
337
  sessionId,
285
338
  userId
286
339
  });
287
340
  if (!conversation) {
288
- if (shouldStream) {
289
- sendErrorResponse(ctx, "conversation not found");
290
- } else {
291
- ctx.status = 404;
292
- ctx.body = { error: "conversation not found" };
293
- }
294
- return next();
341
+ throw new import_utils.ResourceActionError(400, ctx.t("conversation not found"));
342
+ }
343
+ const employee = await getAIEmployee(ctx, employeeName);
344
+ if (!employee) {
345
+ throw new import_utils.ResourceActionError(400, ctx.t("AI employee not found"));
295
346
  }
296
347
  if (!conversation.title) {
297
348
  const textUserMessage = messages.find(
@@ -306,17 +357,12 @@ var aiConversations_default = {
306
357
  await conversation.save();
307
358
  }
308
359
  }
309
- const employee = await getAIEmployee(ctx, employeeName);
310
- if (!employee) {
311
- if (shouldStream) {
312
- sendErrorResponse(ctx, "AI employee not found");
313
- } else {
314
- ctx.status = 404;
315
- ctx.body = { error: "AI employee not found" };
316
- }
317
- return next();
360
+ if (await isReachParallelLimit(ctx)) {
361
+ await saveUserMessages(ctx, sessionId, messages, editingMessageId);
362
+ throw new import_utils.ResourceActionError(400, ctx.t("There are conversations in progress. Please try again later."));
318
363
  }
319
364
  const legacy = conversation.thread === 0;
365
+ const resolvedModel = await plugin.aiEmployeesManager.resolveModel(employee, model);
320
366
  const aiEmployee = new import_ai_employee.AIEmployee({
321
367
  ctx,
322
368
  employee,
@@ -325,7 +371,7 @@ var aiConversations_default = {
325
371
  skillSettings: (_c = conversation.options) == null ? void 0 : _c.skillSettings,
326
372
  tools: (_d = conversation.options) == null ? void 0 : _d.tools,
327
373
  webSearch,
328
- model,
374
+ model: resolvedModel,
329
375
  legacy
330
376
  });
331
377
  if (!editingMessageId) {
@@ -363,11 +409,19 @@ var aiConversations_default = {
363
409
  }
364
410
  } catch (err) {
365
411
  ctx.log.error(err);
412
+ let status = 500;
413
+ let message = ctx.t("Server unexpected error occur");
414
+ if (err instanceof import_utils.ResourceActionError) {
415
+ status = err.status;
416
+ message = err.message;
417
+ } else if (err instanceof Error) {
418
+ status = 500;
419
+ message = err.message;
420
+ }
366
421
  if (shouldStream) {
367
- sendErrorResponse(ctx, err.message || "Tool call error");
422
+ sendErrorResponse(ctx, message);
368
423
  } else {
369
- ctx.status = 500;
370
- ctx.body = { error: err.message || "Tool call error" };
424
+ ctx.throw(status, message);
371
425
  }
372
426
  } finally {
373
427
  await next();
@@ -376,9 +430,6 @@ var aiConversations_default = {
376
430
  async abort(ctx, next) {
377
431
  var _a;
378
432
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
379
- if (!userId) {
380
- return ctx.throw(403);
381
- }
382
433
  const { sessionId } = ctx.action.params.values || {};
383
434
  const plugin = ctx.app.pm.get("ai");
384
435
  const conversation = await plugin.aiConversationsManager.getConversation({
@@ -391,28 +442,99 @@ var aiConversations_default = {
391
442
  plugin.aiEmployeesManager.abortConversation(sessionId);
392
443
  await next();
393
444
  },
394
- async resendMessages(ctx, next) {
395
- var _a, _b, _c, _d;
445
+ async resumeStream(ctx, next) {
446
+ var _a, _b, _c, _d, _e;
396
447
  const plugin = ctx.app.pm.get("ai");
397
448
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
398
- if (!userId) {
399
- return ctx.throw(403);
400
- }
449
+ const abortController = new AbortController();
450
+ const abortStream = () => abortController.abort();
451
+ const shouldStopStream = () => abortController.signal.aborted || ctx.res.destroyed || ctx.res.writableEnded;
401
452
  setupSSEHeaders(ctx);
402
- const { sessionId, webSearch, model } = ctx.action.params.values || {};
403
- let { messageId } = ctx.action.params.values || {};
453
+ const sessionId = ((_b = ctx.action.params) == null ? void 0 : _b.sessionId) || ((_d = (_c = ctx.action.params) == null ? void 0 : _c.values) == null ? void 0 : _d.sessionId) || ((_e = ctx.action.params) == null ? void 0 : _e.filterByTk);
404
454
  if (!sessionId) {
405
455
  sendErrorResponse(ctx, "sessionId is required");
406
- return next();
456
+ return;
407
457
  }
458
+ ctx.req.once("aborted", abortStream);
459
+ ctx.res.once("close", abortStream);
408
460
  try {
409
461
  const conversation = await plugin.aiConversationsManager.getConversation({
410
462
  sessionId,
411
463
  userId
412
464
  });
465
+ if (shouldStopStream()) {
466
+ return;
467
+ }
413
468
  if (!conversation) {
414
469
  sendErrorResponse(ctx, "conversation not found");
415
- return next();
470
+ return;
471
+ }
472
+ const reachLimit = await isReachParallelLimit(ctx);
473
+ if (shouldStopStream()) {
474
+ return;
475
+ }
476
+ let hasChunks = false;
477
+ if (!reachLimit) {
478
+ for await (const chunk of plugin.llmStreamCachedManager.getCached(sessionId).stream({ signal: abortController.signal })) {
479
+ if (shouldStopStream()) {
480
+ break;
481
+ }
482
+ hasChunks = true;
483
+ ctx.res.write(chunk);
484
+ }
485
+ }
486
+ if (!hasChunks && !shouldStopStream()) {
487
+ const currentConversation = await plugin.aiConversationsManager.getConversation({
488
+ sessionId,
489
+ userId
490
+ });
491
+ const llmActiveState = currentConversation == null ? void 0 : currentConversation.llmActiveState;
492
+ if (llmActiveState && llmActiveState !== "idle") {
493
+ ctx.res.write(`data: ${JSON.stringify({ type: "chunks_cache_missing", body: { llmActiveState } })}
494
+
495
+ `);
496
+ }
497
+ }
498
+ } catch (err) {
499
+ if (shouldStopStream()) {
500
+ return;
501
+ }
502
+ ctx.log.error(err);
503
+ sendErrorResponse(ctx, err.message || "Resume stream error");
504
+ return;
505
+ } finally {
506
+ ctx.req.off("aborted", abortStream);
507
+ ctx.res.off("close", abortStream);
508
+ if (!shouldStopStream()) {
509
+ ctx.res.end();
510
+ }
511
+ await next();
512
+ }
513
+ },
514
+ async resendMessages(ctx, next) {
515
+ var _a, _b, _c, _d;
516
+ const plugin = ctx.app.pm.get("ai");
517
+ const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
518
+ const { sessionId, webSearch, model, stream = true } = ctx.action.params.values || {};
519
+ let { messageId } = ctx.action.params.values || {};
520
+ const shouldStream = stream !== false;
521
+ if (shouldStream) {
522
+ setupSSEHeaders(ctx);
523
+ }
524
+ try {
525
+ if (!sessionId) {
526
+ throw new import_utils.ResourceActionError(400, ctx.t("sessionId is required"));
527
+ }
528
+ const conversation = await plugin.aiConversationsManager.getConversation({
529
+ sessionId,
530
+ userId
531
+ });
532
+ if (!conversation) {
533
+ throw new import_utils.ResourceActionError(400, ctx.t("conversation not found"));
534
+ }
535
+ const employee = await getAIEmployee(ctx, conversation.aiEmployeeUsername);
536
+ if (!employee) {
537
+ throw new import_utils.ResourceActionError(400, ctx.t("AI employee not found"));
416
538
  }
417
539
  const resendMessages = [];
418
540
  if (messageId) {
@@ -422,8 +544,7 @@ var aiConversations_default = {
422
544
  }
423
545
  });
424
546
  if (!message) {
425
- sendErrorResponse(ctx, "message not found");
426
- return next();
547
+ throw new import_utils.ResourceActionError(400, ctx.t("message not found"));
427
548
  }
428
549
  } else {
429
550
  const message = await ctx.db.getRepository("aiConversations.messages", sessionId).findOne({
@@ -433,8 +554,7 @@ var aiConversations_default = {
433
554
  sort: ["-messageId"]
434
555
  });
435
556
  if (!message) {
436
- sendErrorResponse(ctx, "No messages to resend");
437
- return next();
557
+ throw new import_utils.ResourceActionError(400, ctx.t("message not found"));
438
558
  }
439
559
  messageId = message.messageId;
440
560
  if (["user", "tool"].includes(message.role)) {
@@ -448,11 +568,10 @@ var aiConversations_default = {
448
568
  });
449
569
  }
450
570
  }
451
- const employee = await getAIEmployee(ctx, conversation.aiEmployeeUsername);
452
- if (!employee) {
453
- sendErrorResponse(ctx, "AI employee not found");
454
- return next();
571
+ if (await isReachParallelLimit(ctx)) {
572
+ throw new import_utils.ResourceActionError(400, ctx.t("There are conversations in progress. Please try again later."));
455
573
  }
574
+ const resolvedModel = await plugin.aiEmployeesManager.resolveModel(employee, model);
456
575
  const aiEmployee = new import_ai_employee.AIEmployee({
457
576
  ctx,
458
577
  employee,
@@ -461,22 +580,40 @@ var aiConversations_default = {
461
580
  skillSettings: (_c = conversation.options) == null ? void 0 : _c.skillSettings,
462
581
  tools: (_d = conversation.options) == null ? void 0 : _d.tools,
463
582
  webSearch,
464
- model
583
+ model: resolvedModel
465
584
  });
466
- await aiEmployee.stream({ messageId, userMessages: resendMessages.length ? resendMessages : void 0 });
585
+ if (shouldStream) {
586
+ await aiEmployee.stream({ messageId, userMessages: resendMessages.length ? resendMessages : void 0 });
587
+ } else {
588
+ ctx.body = await aiEmployee.invoke({
589
+ messageId,
590
+ userMessages: resendMessages.length ? resendMessages : void 0
591
+ });
592
+ }
467
593
  } catch (err) {
468
594
  ctx.log.error(err);
469
- sendErrorResponse(ctx, err.message || "Chat error warning");
595
+ let status = 500;
596
+ let message = ctx.t("Server unexpected error occur");
597
+ if (err instanceof import_utils.ResourceActionError) {
598
+ status = err.status;
599
+ message = err.message;
600
+ } else if (err instanceof Error) {
601
+ status = 500;
602
+ message = err.message;
603
+ }
604
+ if (shouldStream) {
605
+ sendErrorResponse(ctx, message);
606
+ } else {
607
+ ctx.throw(status, message);
608
+ }
609
+ } finally {
610
+ await next();
470
611
  }
471
- await next();
472
612
  },
473
613
  async updateUserDecision(ctx, next) {
474
614
  var _a;
475
615
  const plugin = ctx.app.pm.get("ai");
476
616
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
477
- if (!userId) {
478
- return ctx.throw(403);
479
- }
480
617
  const { sessionId, messageId, toolCallId, userDecision } = ctx.action.params.values || {};
481
618
  if (!sessionId) {
482
619
  ctx.throw(400);
@@ -556,9 +693,6 @@ var aiConversations_default = {
556
693
  async resumeToolCall(ctx, next) {
557
694
  var _a, _b, _c, _d;
558
695
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
559
- if (!userId) {
560
- return ctx.throw(403);
561
- }
562
696
  setupSSEHeaders(ctx);
563
697
  const plugin = ctx.app.pm.get("ai");
564
698
  const { sessionId, messageId, model, webSearch } = ctx.action.params.values || {};
@@ -601,6 +735,7 @@ var aiConversations_default = {
601
735
  sendErrorResponse(ctx, "No tool calls found");
602
736
  return next();
603
737
  }
738
+ const resolvedModel = await plugin.aiEmployeesManager.resolveModel(employee, model);
604
739
  const aiEmployee = new import_ai_employee.AIEmployee({
605
740
  ctx,
606
741
  employee,
@@ -609,7 +744,7 @@ var aiConversations_default = {
609
744
  skillSettings: (_c = conversation.options) == null ? void 0 : _c.skillSettings,
610
745
  tools: (_d = conversation.options) == null ? void 0 : _d.tools,
611
746
  webSearch,
612
- model
747
+ model: resolvedModel
613
748
  });
614
749
  const userDecisions = await plugin.aiConversationsManager.getUserDecisions(messageId);
615
750
  await aiEmployee.stream({
@@ -45,7 +45,9 @@ module.exports = __toCommonJS(aiEmployees_exports);
45
45
  var import_actions = __toESM(require("@nocobase/actions"));
46
46
  var templates = __toESM(require("../ai-employees/templates"));
47
47
  var import_lodash = __toESM(require("lodash"));
48
+ var import_ai_feature_manager = require("../manager/ai-feature-manager");
48
49
  const list = async (ctx, next) => {
50
+ var _a, _b;
49
51
  const { paginate } = ctx.action.params || {};
50
52
  const plugin = ctx.app.pm.get("ai");
51
53
  const builtInManager = plugin.builtInManager;
@@ -58,9 +60,36 @@ const list = async (ctx, next) => {
58
60
  });
59
61
  await import_actions.default.list(ctx, () => {
60
62
  });
61
- let data = ctx.body.rows;
63
+ let data;
62
64
  if (paginate === "false" || paginate === false) {
65
+ ctx.body = ctx.body.map((it) => it.toJSON());
63
66
  data = ctx.body;
67
+ } else {
68
+ ctx.body.rows = ctx.body.rows.map((it) => it.toJSON());
69
+ data = ctx.body.rows;
70
+ }
71
+ const featureEnabled = plugin.features.isFeaturesEnabled(Object.values(import_ai_feature_manager.EEFeatures));
72
+ if (featureEnabled) {
73
+ const knowledgeBaseKeys = import_lodash.default.uniq(
74
+ data.map((it) => {
75
+ var _a2;
76
+ return ((_a2 = it.knowledgeBase) == null ? void 0 : _a2.knowledgeBaseKeys) ?? [];
77
+ }).flatMap((it) => it)
78
+ );
79
+ const knowledgeBaseList = await plugin.features.knowledgeBase.getKnowledgeBase(knowledgeBaseKeys);
80
+ const existedKnowledgeBaseKeys = (knowledgeBaseList == null ? void 0 : knowledgeBaseList.map((it) => it.key)) ?? [];
81
+ for (const row of data) {
82
+ row.missingKnowledgeBaseKeys = [];
83
+ if (!((_b = (_a = row.knowledgeBase) == null ? void 0 : _a.knowledgeBaseKeys) == null ? void 0 : _b.length)) {
84
+ continue;
85
+ }
86
+ for (const k of row.knowledgeBase.knowledgeBaseKeys) {
87
+ if (existedKnowledgeBaseKeys.includes(k)) {
88
+ continue;
89
+ }
90
+ row.missingKnowledgeBaseKeys.push(k);
91
+ }
92
+ }
64
93
  }
65
94
  data.forEach((row) => {
66
95
  if (row.builtIn) {
@@ -153,6 +182,8 @@ const listByUser = async (ctx, next) => {
153
182
  prompt: (_b = (_a = row.userConfigs) == null ? void 0 : _a[0]) == null ? void 0 : _b.prompt
154
183
  },
155
184
  skillSettings,
185
+ chatSettings: row.chatSettings,
186
+ modelSettings: row.modelSettings,
156
187
  builtIn: row.builtIn,
157
188
  category: row.category,
158
189
  deprecated: row.deprecated
@@ -15,16 +15,17 @@ export type VectorStoreProp = {
15
15
  export type KnowledgeBase = {
16
16
  knowledgeBaseType: KnowledgeBaseType;
17
17
  knowledgeBaseOuterId: string;
18
+ key: string;
18
19
  name: string;
19
20
  description: string;
20
21
  vectorStoreProvider: string;
21
- vectorStoreConfigId?: string;
22
+ vectorStoreConfigKey?: string;
22
23
  vectorStoreProps?: VectorStoreProp[];
23
24
  enabled: boolean;
24
25
  };
25
26
  export type VectorStoreConfig = {
26
27
  vectorStoreProvider: string;
27
- vectorStoreConfigId?: string;
28
+ vectorStoreConfigKey?: string;
28
29
  };
29
30
  export type KnowledgeBaseGroup = {
30
31
  vectorStoreConfig: VectorStoreConfig;
@@ -21,3 +21,7 @@ export declare function encodeLocalFile(url: string): Promise<string>;
21
21
  export declare function encodeFile(ctx: Context, url: string): Promise<string>;
22
22
  export declare function parseVariables(ctx: Context, value: string): Promise<any>;
23
23
  export declare const buildTool: (toolsEntry: ToolsEntry) => import("@langchain/core/dist/tools").DynamicTool<any>;
24
+ export declare class ResourceActionError extends Error {
25
+ readonly status: number;
26
+ constructor(status: number, message: string, options?: ErrorOptions);
27
+ }
@@ -36,6 +36,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
36
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
37
  var utils_exports = {};
38
38
  __export(utils_exports, {
39
+ ResourceActionError: () => ResourceActionError,
39
40
  buildTool: () => buildTool,
40
41
  encodeFile: () => encodeFile,
41
42
  encodeLocalFile: () => encodeLocalFile,
@@ -179,8 +180,16 @@ const buildTool = (toolsEntry) => {
179
180
  }
180
181
  );
181
182
  };
183
+ class ResourceActionError extends Error {
184
+ constructor(status, message, options) {
185
+ super(message, options);
186
+ this.status = status;
187
+ this.name = "ResourceActionError";
188
+ }
189
+ }
182
190
  // Annotate the CommonJS export names for ESM import in node:
183
191
  0 && (module.exports = {
192
+ ResourceActionError,
184
193
  buildTool,
185
194
  encodeFile,
186
195
  encodeLocalFile,