@nocobase/plugin-ai 2.1.0-alpha.34 → 2.1.0-alpha.36

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 (104) 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/api/cli/env/remove.md +5 -3
  22. package/dist/ai/docs/nocobase/cluster-mode/index.md +5 -1
  23. package/dist/ai/docs/nocobase/cluster-mode/preparations.md +58 -3
  24. package/dist/ai/docs/nocobase/get-started/deployment/how-to-deploy-nocobase-faster.mdx +384 -0
  25. package/dist/ai/docs/nocobase/get-started/upgrading/docker.md +1 -1
  26. package/dist/ai/docs/nocobase/interface-builder/actions/types/js-action.md +1 -1
  27. package/dist/ai/docs/nocobase/interface-builder/actions/types/js-item.md +1 -1
  28. package/dist/ai/docs/nocobase/interface-builder/blocks/other-blocks/js-block.md +1 -1
  29. package/dist/ai/docs/nocobase/interface-builder/fields/specific/js-column.md +1 -1
  30. package/dist/ai/docs/nocobase/interface-builder/fields/specific/js-field.md +1 -1
  31. package/dist/ai/docs/nocobase/interface-builder/fields/specific/js-item.md +1 -1
  32. package/dist/ai/docs/nocobase/security/guide.md +13 -1
  33. package/dist/ai/docs/nocobase/system-management/localization/index.md +25 -1
  34. package/dist/client/462.1708385b148779cd.js +10 -0
  35. package/dist/client/{559.39872901b9053629.js → 559.585f80c3bcea0bed.js} +1 -1
  36. package/dist/client/646.b0ed728921b007d4.js +10 -0
  37. package/dist/client/{927.ac9ee9a8c1cb4f1d.js → 927.d95c74ebb8fd51c9.js} +1 -1
  38. package/dist/client/ai-employees/admin/ModelSettings.d.ts +10 -0
  39. package/dist/client/ai-employees/admin/hooks.d.ts +1 -1
  40. package/dist/client/ai-employees/avatars.d.ts +9 -783
  41. package/dist/client/ai-employees/chatbox/model.d.ts +6 -3
  42. package/dist/client/ai-employees/types.d.ts +23 -0
  43. package/dist/client/features/vector-database-provider.d.ts +1 -1
  44. package/dist/client/index.js +4 -4
  45. package/dist/client/llm-services/component/EnabledModelsSelect.d.ts +1 -14
  46. package/dist/client-v2/ai-employees/AIEmployeeShortcut.d.ts +21 -0
  47. package/dist/client-v2/ai-employees/ProfileCard.d.ts +17 -0
  48. package/dist/client-v2/ai-employees/avatars.d.ts +783 -0
  49. package/dist/client-v2/ai-employees/types.d.ts +20 -0
  50. package/dist/client-v2/index.d.ts +17 -0
  51. package/dist/client-v2/index.js +10 -0
  52. package/dist/client-v2/llm-services/model-label.d.ts +22 -0
  53. package/dist/collections/ai-employees.d.ts +2 -1
  54. package/dist/collections/ai-employees.js +1 -1
  55. package/dist/externalVersion.js +17 -17
  56. package/dist/locale/en-US.json +15 -1
  57. package/dist/locale/zh-CN.json +15 -1
  58. package/dist/node_modules/@langchain/xai/package.json +1 -1
  59. package/dist/node_modules/fs-extra/package.json +1 -1
  60. package/dist/node_modules/jsonrepair/package.json +1 -1
  61. package/dist/node_modules/just-bash/package.json +1 -1
  62. package/dist/node_modules/nodejs-snowflake/package.json +1 -1
  63. package/dist/node_modules/openai/package.json +1 -1
  64. package/dist/node_modules/zod/package.json +1 -1
  65. package/dist/server/ai-employees/ai-conversations.d.ts +1 -0
  66. package/dist/server/ai-employees/ai-conversations.js +4 -1
  67. package/dist/server/ai-employees/ai-employee.d.ts +15 -1
  68. package/dist/server/ai-employees/ai-employee.js +140 -9
  69. package/dist/server/ai-employees/ai-employees-manager.d.ts +4 -0
  70. package/dist/server/ai-employees/ai-employees-manager.js +41 -0
  71. package/dist/server/ai-employees/ai-knowledge-base.js +7 -7
  72. package/dist/server/ai-employees/middleware/conversation.d.ts +1 -0
  73. package/dist/server/ai-employees/middleware/conversation.js +4 -2
  74. package/dist/server/ai-employees/sub-agents/dispatcher.js +2 -4
  75. package/dist/server/ai-employees/utils.d.ts +6 -3
  76. package/dist/server/ai-employees/utils.js +7 -1
  77. package/dist/server/features/knowledge-base.d.ts +3 -2
  78. package/dist/server/index.d.ts +2 -0
  79. package/dist/server/index.js +3 -0
  80. package/dist/server/llm-providers/common/reasoning.d.ts +2 -0
  81. package/dist/server/llm-providers/common/reasoning.js +15 -2
  82. package/dist/server/llm-providers/dashscope.d.ts +2 -1
  83. package/dist/server/llm-providers/dashscope.js +39 -0
  84. package/dist/server/llm-providers/deepseek.js +2 -0
  85. package/dist/server/llm-providers/provider.d.ts +15 -1
  86. package/dist/server/llm-providers/provider.js +21 -2
  87. package/dist/server/manager/ai-chat-conversation.js +3 -4
  88. package/dist/server/manager/ai-manager.d.ts +17 -0
  89. package/dist/server/manager/ai-manager.js +65 -0
  90. package/dist/server/manager/llm-stream-manager.d.ts +16 -10
  91. package/dist/server/manager/llm-stream-manager.js +121 -27
  92. package/dist/server/migrations/20260407170416-ai-employee-knowledge-base-add-key.d.ts +14 -0
  93. package/dist/server/migrations/20260407170416-ai-employee-knowledge-base-add-key.js +61 -0
  94. package/dist/server/resource/ai.js +1 -41
  95. package/dist/server/resource/aiConversations.d.ts +12 -13
  96. package/dist/server/resource/aiConversations.js +129 -121
  97. package/dist/server/resource/aiEmployees.js +32 -1
  98. package/dist/server/types/knowledge-base.type.d.ts +3 -2
  99. package/dist/server/utils.d.ts +4 -0
  100. package/dist/server/utils.js +9 -0
  101. package/dist/server/workflow/nodes/employee/index.js +4 -2
  102. package/package.json +2 -2
  103. package/dist/client/343.6f36d97dd122c5b6.js +0 -10
  104. package/dist/client/646.5860101cb28c8272.js +0 -10
@@ -0,0 +1,61 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ var __defProp = Object.defineProperty;
11
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
+ var __getOwnPropNames = Object.getOwnPropertyNames;
13
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
27
+ var ai_employee_knowledge_base_add_key_exports = {};
28
+ __export(ai_employee_knowledge_base_add_key_exports, {
29
+ default: () => ai_employee_knowledge_base_add_key_default
30
+ });
31
+ module.exports = __toCommonJS(ai_employee_knowledge_base_add_key_exports);
32
+ var import_server = require("@nocobase/server");
33
+ class ai_employee_knowledge_base_add_key_default extends import_server.Migration {
34
+ on = "afterSync";
35
+ // 'beforeLoad' or 'afterLoad'
36
+ appVersion = "<2.2.0";
37
+ async up() {
38
+ var _a, _b, _c, _d;
39
+ const aiEmployeesRepo = this.app.db.getRepository("aiEmployees");
40
+ const aiEmployeeList = await aiEmployeesRepo.find();
41
+ for (const item of aiEmployeeList) {
42
+ if (!((_b = (_a = item.knowledgeBase) == null ? void 0 : _a.knowledgeBaseIds) == null ? void 0 : _b.length)) {
43
+ continue;
44
+ }
45
+ if ((_d = (_c = item.knowledgeBase) == null ? void 0 : _c.knowledgeBaseKeys) == null ? void 0 : _d.length) {
46
+ continue;
47
+ }
48
+ await aiEmployeesRepo.update({
49
+ values: {
50
+ knowledgeBase: {
51
+ ...item.knowledgeBase,
52
+ knowledgeBaseKeys: item.knowledgeBase.knowledgeBaseIds.map((it) => String(it))
53
+ }
54
+ },
55
+ filter: {
56
+ username: item.username
57
+ }
58
+ });
59
+ }
60
+ }
61
+ }
@@ -40,7 +40,6 @@ __export(ai_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(ai_exports);
42
42
  var import_lodash = __toESM(require("lodash"));
43
- var import_recommended_models = require("../../common/recommended-models");
44
43
  const aiResource = {
45
44
  name: "ai",
46
45
  actions: {
@@ -157,46 +156,7 @@ const aiResource = {
157
156
  },
158
157
  listAllEnabledModels: async (ctx, next) => {
159
158
  const plugin = ctx.app.pm.get("ai");
160
- const services = await ctx.db.getRepository("llmServices").find({ sort: "sort" });
161
- const llmServices = services.filter((service) => service.enabled !== false).map((service) => {
162
- const raw = service.enabledModels;
163
- let enabledModels;
164
- if (raw && typeof raw === "object" && !Array.isArray(raw) && raw.mode) {
165
- if (raw.mode === "recommended") {
166
- enabledModels = (0, import_recommended_models.getRecommendedModels)(service.provider);
167
- } else {
168
- enabledModels = (raw.models || []).filter((m) => m.value).map((m) => ({
169
- label: m.label || m.value,
170
- value: m.value
171
- }));
172
- }
173
- } else if (Array.isArray(raw)) {
174
- if (raw.length === 0) {
175
- enabledModels = (0, import_recommended_models.getRecommendedModels)(service.provider);
176
- } else {
177
- enabledModels = raw.map((id) => ({ label: id, value: id }));
178
- }
179
- } else {
180
- enabledModels = (0, import_recommended_models.getRecommendedModels)(service.provider);
181
- }
182
- if (enabledModels.length === 0) {
183
- return null;
184
- }
185
- const providerMeta = plugin.aiManager.llmProviders.get(service.provider);
186
- const P = providerMeta.provider;
187
- const p = new P({ app: ctx.app });
188
- const isToolConflict = p.isToolConflict();
189
- return {
190
- llmService: service.name,
191
- llmServiceTitle: service.title,
192
- provider: service.provider,
193
- providerTitle: providerMeta == null ? void 0 : providerMeta.title,
194
- enabledModels,
195
- supportWebSearch: (providerMeta == null ? void 0 : providerMeta.supportWebSearch) ?? false,
196
- isToolConflict
197
- };
198
- }).filter(Boolean);
199
- ctx.body = llmServices;
159
+ ctx.body = await plugin.aiManager.listAllEnabledModels();
200
160
  await next();
201
161
  }
202
162
  }
@@ -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
  };
@@ -43,6 +43,7 @@ var import_actions = __toESM(require("@nocobase/actions"));
43
43
  var import_database = require("@nocobase/database");
44
44
  var import_utils = require("../utils");
45
45
  var import_ai_employee = require("../ai-employees/ai-employee");
46
+ var import_ai_chat_conversation = require("../manager/ai-chat-conversation");
46
47
  async function getAIEmployee(ctx, username) {
47
48
  var _a;
48
49
  const filter = {
@@ -67,12 +68,17 @@ function setupSSEHeaders(ctx) {
67
68
  function sendErrorResponse(ctx, errorMessage) {
68
69
  (0, import_utils.sendSSEError)(ctx, errorMessage);
69
70
  }
70
- async function parallelConversationsLimit(ctx, next) {
71
+ async function loginInCheck(ctx, next) {
71
72
  var _a;
72
73
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
73
74
  if (!userId) {
74
75
  return ctx.throw(403);
75
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;
76
82
  const activeStreamCount = await ctx.db.getModel("aiConversations").count({
77
83
  where: {
78
84
  userId,
@@ -82,27 +88,32 @@ async function parallelConversationsLimit(ctx, next) {
82
88
  }
83
89
  }
84
90
  });
85
- if (activeStreamCount > 2) {
86
- sendErrorResponse(ctx, ctx.t("There are conversations in progress. Please try again later."));
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) {
87
96
  return;
88
97
  }
89
- await next();
90
- }
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
+ };
91
106
  var aiConversations_default = {
92
107
  name: "aiConversations",
93
108
  middlewares: [
94
109
  {
95
- only: ["sendMessages", "resendMessages", "resumeStream"],
96
- handler: parallelConversationsLimit
110
+ handler: loginInCheck
97
111
  }
98
112
  ],
99
113
  actions: {
100
114
  async list(ctx, next) {
101
115
  var _a;
102
116
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
103
- if (!userId) {
104
- return ctx.throw(403);
105
- }
106
117
  const filter = ctx.action.params.filter || {};
107
118
  ctx.action.mergeParams({
108
119
  filter: {
@@ -117,9 +128,6 @@ var aiConversations_default = {
117
128
  async unreadCount(ctx, next) {
118
129
  var _a;
119
130
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
120
- if (!userId) {
121
- return ctx.throw(403);
122
- }
123
131
  const count = await ctx.db.getModel("aiConversations").count({
124
132
  where: {
125
133
  userId,
@@ -136,9 +144,6 @@ var aiConversations_default = {
136
144
  async unreadCounts(ctx, next) {
137
145
  var _a;
138
146
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
139
- if (!userId) {
140
- return ctx.throw(403);
141
- }
142
147
  const [conversationUnreadCount, workflowTaskUnreadCount] = await Promise.all([
143
148
  ctx.db.getModel("aiConversations").count({
144
149
  where: {
@@ -165,10 +170,7 @@ var aiConversations_default = {
165
170
  var _a;
166
171
  const plugin = ctx.app.pm.get("ai");
167
172
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
168
- if (!userId) {
169
- return ctx.throw(403);
170
- }
171
- const { aiEmployee, systemMessage, skillSettings, conversationSettings } = ctx.action.params.values || {};
173
+ const { aiEmployee, systemMessage, skillSettings, conversationSettings, modelSettings } = ctx.action.params.values || {};
172
174
  const employee = await getAIEmployee(ctx, aiEmployee.username);
173
175
  if (!employee) {
174
176
  ctx.throw(400, "AI employee not found");
@@ -180,7 +182,8 @@ var aiConversations_default = {
180
182
  options: {
181
183
  systemMessage,
182
184
  skillSettings,
183
- conversationSettings
185
+ conversationSettings,
186
+ modelSettings
184
187
  }
185
188
  });
186
189
  } catch (error) {
@@ -195,9 +198,6 @@ var aiConversations_default = {
195
198
  var _a;
196
199
  const plugin = ctx.app.pm.get("ai");
197
200
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
198
- if (!userId) {
199
- return ctx.throw(403);
200
- }
201
201
  const { filterByTk: sessionId } = ctx.action.params;
202
202
  const { title } = ctx.action.params.values || {};
203
203
  ctx.body = await plugin.aiConversationsManager.update({ userId, sessionId, title });
@@ -207,22 +207,19 @@ var aiConversations_default = {
207
207
  var _a;
208
208
  const plugin = ctx.app.pm.get("ai");
209
209
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
210
- if (!userId) {
211
- return ctx.throw(403);
212
- }
213
210
  const { filterByTk: sessionId } = ctx.action.params;
214
211
  if (!sessionId) {
215
212
  return ctx.throw(400, "invalid sessionId");
216
213
  }
217
- const { systemMessage, skillSettings, conversationSettings } = ctx.action.params.values || {};
218
- if (!systemMessage && !skillSettings && !conversationSettings) {
214
+ const { systemMessage, skillSettings, conversationSettings, modelSettings } = ctx.action.params.values || {};
215
+ if (!systemMessage && !skillSettings && !conversationSettings && !modelSettings) {
219
216
  return ctx.throw(400, "invalid options");
220
217
  }
221
218
  try {
222
219
  ctx.body = await plugin.aiConversationsManager.update({
223
220
  userId,
224
221
  sessionId,
225
- options: { systemMessage, skillSettings, conversationSettings }
222
+ options: { systemMessage, skillSettings, conversationSettings, modelSettings }
226
223
  });
227
224
  } catch (error) {
228
225
  if (error.message === "invalid sessionId") {
@@ -235,9 +232,6 @@ var aiConversations_default = {
235
232
  async destroy(ctx, next) {
236
233
  var _a;
237
234
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
238
- if (!userId) {
239
- return ctx.throw(403);
240
- }
241
235
  ctx.action.mergeParams({
242
236
  filter: {
243
237
  userId
@@ -249,9 +243,6 @@ var aiConversations_default = {
249
243
  var _a, _b;
250
244
  const plugin = ctx.app.pm.get("ai");
251
245
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
252
- if (!userId) {
253
- return ctx.throw(403);
254
- }
255
246
  const { sessionId, cursor, updateRead: originalUpdateRead } = ctx.action.params || {};
256
247
  if (!sessionId) {
257
248
  ctx.throw(400);
@@ -278,9 +269,6 @@ var aiConversations_default = {
278
269
  var _a;
279
270
  const plugin = ctx.app.pm.get("ai");
280
271
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
281
- if (!userId) {
282
- return ctx.throw(403);
283
- }
284
272
  const {
285
273
  sessionId,
286
274
  messageId,
@@ -319,11 +307,8 @@ var aiConversations_default = {
319
307
  },
320
308
  async sendMessages(ctx, next) {
321
309
  var _a, _b, _c, _d;
322
- const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
323
- if (!userId) {
324
- return ctx.throw(403);
325
- }
326
310
  const plugin = ctx.app.pm.get("ai");
311
+ const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
327
312
  const {
328
313
  sessionId,
329
314
  aiEmployee: employeeName,
@@ -337,38 +322,27 @@ var aiConversations_default = {
337
322
  if (shouldStream) {
338
323
  setupSSEHeaders(ctx);
339
324
  }
340
- if (!sessionId) {
341
- if (shouldStream) {
342
- sendErrorResponse(ctx, "sessionId is required");
343
- } else {
344
- ctx.status = 400;
345
- ctx.body = { error: "sessionId is required" };
325
+ try {
326
+ if (!sessionId) {
327
+ throw new import_utils.ResourceActionError(400, ctx.t("sessionId is required"));
346
328
  }
347
- return next();
348
- }
349
- const userMessage = messages.find((message) => message.role === "user");
350
- if (!userMessage) {
351
- if (shouldStream) {
352
- sendErrorResponse(ctx, "user message is required");
353
- } else {
354
- ctx.status = 400;
355
- 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"));
356
335
  }
357
- return next();
358
- }
359
- try {
360
336
  const conversation = await plugin.aiConversationsManager.getConversation({
361
337
  sessionId,
362
338
  userId
363
339
  });
364
340
  if (!conversation) {
365
- if (shouldStream) {
366
- sendErrorResponse(ctx, "conversation not found");
367
- } else {
368
- ctx.status = 404;
369
- ctx.body = { error: "conversation not found" };
370
- }
371
- 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"));
372
346
  }
373
347
  if (!conversation.title) {
374
348
  const textUserMessage = messages.find(
@@ -383,17 +357,12 @@ var aiConversations_default = {
383
357
  await conversation.save();
384
358
  }
385
359
  }
386
- const employee = await getAIEmployee(ctx, employeeName);
387
- if (!employee) {
388
- if (shouldStream) {
389
- sendErrorResponse(ctx, "AI employee not found");
390
- } else {
391
- ctx.status = 404;
392
- ctx.body = { error: "AI employee not found" };
393
- }
394
- 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."));
395
363
  }
396
364
  const legacy = conversation.thread === 0;
365
+ const resolvedModel = await plugin.aiEmployeesManager.resolveModel(employee, model);
397
366
  const aiEmployee = new import_ai_employee.AIEmployee({
398
367
  ctx,
399
368
  employee,
@@ -402,7 +371,7 @@ var aiConversations_default = {
402
371
  skillSettings: (_c = conversation.options) == null ? void 0 : _c.skillSettings,
403
372
  tools: (_d = conversation.options) == null ? void 0 : _d.tools,
404
373
  webSearch,
405
- model,
374
+ model: resolvedModel,
406
375
  legacy
407
376
  });
408
377
  if (!editingMessageId) {
@@ -440,11 +409,19 @@ var aiConversations_default = {
440
409
  }
441
410
  } catch (err) {
442
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
+ }
443
421
  if (shouldStream) {
444
- sendErrorResponse(ctx, err.message || "Tool call error");
422
+ sendErrorResponse(ctx, message);
445
423
  } else {
446
- ctx.status = 500;
447
- ctx.body = { error: err.message || "Tool call error" };
424
+ ctx.throw(status, message);
448
425
  }
449
426
  } finally {
450
427
  await next();
@@ -453,9 +430,6 @@ var aiConversations_default = {
453
430
  async abort(ctx, next) {
454
431
  var _a;
455
432
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
456
- if (!userId) {
457
- return ctx.throw(403);
458
- }
459
433
  const { sessionId } = ctx.action.params.values || {};
460
434
  const plugin = ctx.app.pm.get("ai");
461
435
  const conversation = await plugin.aiConversationsManager.getConversation({
@@ -472,30 +446,44 @@ var aiConversations_default = {
472
446
  var _a, _b, _c, _d, _e;
473
447
  const plugin = ctx.app.pm.get("ai");
474
448
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
475
- if (!userId) {
476
- return ctx.throw(403);
477
- }
449
+ const abortController = new AbortController();
450
+ const abortStream = () => abortController.abort();
451
+ const shouldStopStream = () => abortController.signal.aborted || ctx.res.destroyed || ctx.res.writableEnded;
478
452
  setupSSEHeaders(ctx);
479
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);
480
454
  if (!sessionId) {
481
455
  sendErrorResponse(ctx, "sessionId is required");
482
456
  return;
483
457
  }
458
+ ctx.req.once("aborted", abortStream);
459
+ ctx.res.once("close", abortStream);
484
460
  try {
485
461
  const conversation = await plugin.aiConversationsManager.getConversation({
486
462
  sessionId,
487
463
  userId
488
464
  });
465
+ if (shouldStopStream()) {
466
+ return;
467
+ }
489
468
  if (!conversation) {
490
469
  sendErrorResponse(ctx, "conversation not found");
491
470
  return;
492
471
  }
472
+ const reachLimit = await isReachParallelLimit(ctx);
473
+ if (shouldStopStream()) {
474
+ return;
475
+ }
493
476
  let hasChunks = false;
494
- for await (const chunk of plugin.llmStreamCachedManager.getCached(sessionId).stream()) {
495
- hasChunks = true;
496
- ctx.res.write(chunk);
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
+ }
497
485
  }
498
- if (!hasChunks) {
486
+ if (!hasChunks && !shouldStopStream()) {
499
487
  const currentConversation = await plugin.aiConversationsManager.getConversation({
500
488
  sessionId,
501
489
  userId
@@ -508,11 +496,16 @@ var aiConversations_default = {
508
496
  }
509
497
  }
510
498
  } catch (err) {
499
+ if (shouldStopStream()) {
500
+ return;
501
+ }
511
502
  ctx.log.error(err);
512
503
  sendErrorResponse(ctx, err.message || "Resume stream error");
513
504
  return;
514
505
  } finally {
515
- if (!ctx.res.writableEnded) {
506
+ ctx.req.off("aborted", abortStream);
507
+ ctx.res.off("close", abortStream);
508
+ if (!shouldStopStream()) {
516
509
  ctx.res.end();
517
510
  }
518
511
  await next();
@@ -522,24 +515,26 @@ var aiConversations_default = {
522
515
  var _a, _b, _c, _d;
523
516
  const plugin = ctx.app.pm.get("ai");
524
517
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
525
- if (!userId) {
526
- return ctx.throw(403);
527
- }
528
- setupSSEHeaders(ctx);
529
- const { sessionId, webSearch, model } = ctx.action.params.values || {};
518
+ const { sessionId, webSearch, model, stream = true } = ctx.action.params.values || {};
530
519
  let { messageId } = ctx.action.params.values || {};
531
- if (!sessionId) {
532
- sendErrorResponse(ctx, "sessionId is required");
533
- return next();
520
+ const shouldStream = stream !== false;
521
+ if (shouldStream) {
522
+ setupSSEHeaders(ctx);
534
523
  }
535
524
  try {
525
+ if (!sessionId) {
526
+ throw new import_utils.ResourceActionError(400, ctx.t("sessionId is required"));
527
+ }
536
528
  const conversation = await plugin.aiConversationsManager.getConversation({
537
529
  sessionId,
538
530
  userId
539
531
  });
540
532
  if (!conversation) {
541
- sendErrorResponse(ctx, "conversation not found");
542
- return next();
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"));
543
538
  }
544
539
  const resendMessages = [];
545
540
  if (messageId) {
@@ -549,8 +544,7 @@ var aiConversations_default = {
549
544
  }
550
545
  });
551
546
  if (!message) {
552
- sendErrorResponse(ctx, "message not found");
553
- return next();
547
+ throw new import_utils.ResourceActionError(400, ctx.t("message not found"));
554
548
  }
555
549
  } else {
556
550
  const message = await ctx.db.getRepository("aiConversations.messages", sessionId).findOne({
@@ -560,8 +554,7 @@ var aiConversations_default = {
560
554
  sort: ["-messageId"]
561
555
  });
562
556
  if (!message) {
563
- sendErrorResponse(ctx, "No messages to resend");
564
- return next();
557
+ throw new import_utils.ResourceActionError(400, ctx.t("message not found"));
565
558
  }
566
559
  messageId = message.messageId;
567
560
  if (["user", "tool"].includes(message.role)) {
@@ -575,11 +568,10 @@ var aiConversations_default = {
575
568
  });
576
569
  }
577
570
  }
578
- const employee = await getAIEmployee(ctx, conversation.aiEmployeeUsername);
579
- if (!employee) {
580
- sendErrorResponse(ctx, "AI employee not found");
581
- 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."));
582
573
  }
574
+ const resolvedModel = await plugin.aiEmployeesManager.resolveModel(employee, model);
583
575
  const aiEmployee = new import_ai_employee.AIEmployee({
584
576
  ctx,
585
577
  employee,
@@ -588,22 +580,40 @@ var aiConversations_default = {
588
580
  skillSettings: (_c = conversation.options) == null ? void 0 : _c.skillSettings,
589
581
  tools: (_d = conversation.options) == null ? void 0 : _d.tools,
590
582
  webSearch,
591
- model
583
+ model: resolvedModel
592
584
  });
593
- 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
+ }
594
593
  } catch (err) {
595
594
  ctx.log.error(err);
596
- 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();
597
611
  }
598
- await next();
599
612
  },
600
613
  async updateUserDecision(ctx, next) {
601
614
  var _a;
602
615
  const plugin = ctx.app.pm.get("ai");
603
616
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
604
- if (!userId) {
605
- return ctx.throw(403);
606
- }
607
617
  const { sessionId, messageId, toolCallId, userDecision } = ctx.action.params.values || {};
608
618
  if (!sessionId) {
609
619
  ctx.throw(400);
@@ -683,9 +693,6 @@ var aiConversations_default = {
683
693
  async resumeToolCall(ctx, next) {
684
694
  var _a, _b, _c, _d;
685
695
  const userId = (_a = ctx.auth) == null ? void 0 : _a.user.id;
686
- if (!userId) {
687
- return ctx.throw(403);
688
- }
689
696
  setupSSEHeaders(ctx);
690
697
  const plugin = ctx.app.pm.get("ai");
691
698
  const { sessionId, messageId, model, webSearch } = ctx.action.params.values || {};
@@ -728,6 +735,7 @@ var aiConversations_default = {
728
735
  sendErrorResponse(ctx, "No tool calls found");
729
736
  return next();
730
737
  }
738
+ const resolvedModel = await plugin.aiEmployeesManager.resolveModel(employee, model);
731
739
  const aiEmployee = new import_ai_employee.AIEmployee({
732
740
  ctx,
733
741
  employee,
@@ -736,7 +744,7 @@ var aiConversations_default = {
736
744
  skillSettings: (_c = conversation.options) == null ? void 0 : _c.skillSettings,
737
745
  tools: (_d = conversation.options) == null ? void 0 : _d.tools,
738
746
  webSearch,
739
- model
747
+ model: resolvedModel
740
748
  });
741
749
  const userDecisions = await plugin.aiConversationsManager.getUserDecisions(messageId);
742
750
  await aiEmployee.stream({