@nocobase/plugin-ai 2.1.0-alpha.20 → 2.1.0-alpha.21

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 (96) hide show
  1. package/dist/ai/tools/knowledge-base-retrieve.d.ts +10 -0
  2. package/dist/ai/tools/knowledge-base-retrieve.js +94 -0
  3. package/dist/client/486.77c26e2e7f8daf28.js +10 -0
  4. package/dist/client/646.ef9d7c2ea8641044.js +10 -0
  5. package/dist/client/ai-employees/chatbox/AIEmployeeSwitch.d.ts +3 -1
  6. package/dist/client/ai-employees/chatbox/HintMessageHeader.d.ts +10 -0
  7. package/dist/client/ai-employees/chatbox/ModelSwitcher.d.ts +3 -1
  8. package/dist/client/ai-employees/chatbox/SearchSwitch.d.ts +3 -1
  9. package/dist/client/ai-employees/chatbox/Upload.d.ts +3 -1
  10. package/dist/client/ai-employees/chatbox/conversations/ConversationsList.d.ts +27 -0
  11. package/dist/client/ai-employees/chatbox/conversations/WorkflowTasksList.d.ts +31 -0
  12. package/dist/client/ai-employees/chatbox/conversations/common.d.ts +43 -0
  13. package/dist/{server/document-loader/loader.worker.d.ts → client/ai-employees/chatbox/conversations/index.d.ts} +1 -1
  14. package/dist/client/ai-employees/chatbox/hooks/useWorkflowTasks.d.ts +24 -0
  15. package/dist/client/ai-employees/chatbox/stores/chat-box.d.ts +8 -0
  16. package/dist/client/ai-employees/chatbox/stores/chat-conversations.d.ts +4 -0
  17. package/dist/client/ai-employees/chatbox/stores/workflow-tasks.d.ts +41 -0
  18. package/dist/client/ai-employees/workflow-tasks/tools/index.d.ts +10 -0
  19. package/dist/client/ai-employees/workflow-tasks/ui/WorkflowTaskOutputCard.d.ts +11 -0
  20. package/dist/client/components/ListCollapse.d.ts +28 -0
  21. package/dist/client/index.js +7 -7
  22. package/dist/client/repositories/AIConfigRepository.d.ts +3 -2
  23. package/dist/client/workflow/nodes/employee/components/AIEmployeeSelect.d.ts +10 -0
  24. package/dist/client/workflow/nodes/employee/components/assigness.d.ts +11 -0
  25. package/dist/client/workflow/nodes/employee/components/file-inputs.d.ts +10 -0
  26. package/dist/client/workflow/nodes/employee/components/message-inputs.d.ts +12 -0
  27. package/dist/client/workflow/nodes/employee/components/model-options.d.ts +10 -0
  28. package/dist/client/workflow/nodes/employee/components/skill-settings.d.ts +10 -0
  29. package/dist/client/workflow/nodes/employee/components/structured-output.d.ts +10 -0
  30. package/dist/client/workflow/nodes/employee/components/users-select.d.ts +15 -0
  31. package/dist/client/workflow/nodes/employee/components/web-search-options.d.ts +10 -0
  32. package/dist/client/workflow/nodes/employee/configuration.d.ts +12 -0
  33. package/dist/client/workflow/nodes/employee/flow-models/feedback.d.ts +13 -0
  34. package/dist/client/workflow/nodes/employee/flow-models/task.d.ts +13 -0
  35. package/dist/client/workflow/nodes/employee/index.d.ts +7 -31
  36. package/dist/externalVersion.js +14 -15
  37. package/dist/locale/en-US.json +44 -1
  38. package/dist/locale/zh-CN.json +45 -1
  39. package/dist/node_modules/fast-glob/out/index.js +8 -8
  40. package/dist/node_modules/fast-glob/package.json +1 -1
  41. package/dist/node_modules/flexsearch/dist/flexsearch.bundle.min.js +2 -2
  42. package/dist/node_modules/flexsearch/package.json +1 -1
  43. package/dist/node_modules/fs-extra/lib/index.js +1 -1
  44. package/dist/node_modules/fs-extra/package.json +1 -1
  45. package/dist/node_modules/nodejs-snowflake/nodejs_snowflake.js +1 -1
  46. package/dist/node_modules/nodejs-snowflake/package.json +1 -1
  47. package/dist/node_modules/openai/index.js +1 -1
  48. package/dist/node_modules/openai/package.json +1 -1
  49. package/dist/node_modules/zod/index.cjs +1 -1
  50. package/dist/node_modules/zod/package.json +1 -1
  51. package/dist/server/ai-employees/ai-conversations.d.ts +10 -4
  52. package/dist/server/ai-employees/ai-conversations.js +52 -14
  53. package/dist/server/ai-employees/ai-employee.d.ts +8 -10
  54. package/dist/server/ai-employees/ai-employee.js +130 -145
  55. package/dist/server/ai-employees/ai-knowledge-base.d.ts +28 -0
  56. package/dist/server/ai-employees/ai-knowledge-base.js +167 -0
  57. package/dist/server/ai-employees/middleware/index.d.ts +1 -0
  58. package/dist/server/ai-employees/middleware/index.js +3 -1
  59. package/dist/server/ai-employees/middleware/workflow-history.d.ts +22 -0
  60. package/dist/server/ai-employees/middleware/workflow-history.js +173 -0
  61. package/dist/server/collections/ai-conversations.js +12 -0
  62. package/dist/server/collections/ai-workflow-tasks.d.ts +10 -0
  63. package/dist/server/collections/ai-workflow-tasks.js +112 -0
  64. package/dist/server/collections/users-ai-workflow-tasks.d.ts +10 -0
  65. package/dist/server/collections/users-ai-workflow-tasks.js +44 -0
  66. package/dist/server/document-loader/constants.d.ts +1 -2
  67. package/dist/server/document-loader/constants.js +6 -1
  68. package/dist/server/document-loader/loader.d.ts +0 -1
  69. package/dist/server/document-loader/loader.js +2 -55
  70. package/dist/server/document-loader/types.d.ts +0 -1
  71. package/dist/server/llm-providers/provider.js +1 -1
  72. package/dist/server/manager/built-in-manager.js +5 -4
  73. package/dist/server/plugin.d.ts +2 -0
  74. package/dist/server/plugin.js +10 -0
  75. package/dist/server/resource/aiConversations.js +29 -35
  76. package/dist/server/resource/aiWorkflowTasks.d.ts +12 -0
  77. package/dist/server/resource/aiWorkflowTasks.js +290 -0
  78. package/dist/server/utils.js +3 -2
  79. package/dist/server/workflow/nodes/employee/files.d.ts +16 -0
  80. package/dist/server/workflow/nodes/employee/files.js +125 -0
  81. package/dist/server/workflow/nodes/employee/handler.d.ts +11 -0
  82. package/dist/server/workflow/nodes/employee/handler.js +107 -0
  83. package/dist/server/workflow/nodes/employee/index.d.ts +17 -0
  84. package/dist/server/workflow/nodes/employee/index.js +391 -0
  85. package/dist/server/workflow/nodes/employee/tools.d.ts +12 -0
  86. package/dist/server/workflow/nodes/employee/tools.js +133 -0
  87. package/dist/server/workflow/nodes/employee/types.d.ts +35 -0
  88. package/dist/server/workflow/nodes/employee/types.js +24 -0
  89. package/dist/server/workflow/utils.d.ts +14 -0
  90. package/dist/server/workflow/utils.js +111 -0
  91. package/package.json +2 -2
  92. package/dist/client/30.4f30511a3059c422.js +0 -10
  93. package/dist/server/document-loader/loader.worker.js +0 -68
  94. package/dist/server/document-loader/vendor/langchain/document_loaders/fs/text.d.ts +0 -20
  95. package/dist/server/document-loader/vendor/langchain/document_loaders/fs/text.js +0 -96
  96. /package/dist/client/ai-employees/chatbox/{Conversations.d.ts → conversations/Conversations.d.ts} +0 -0
@@ -0,0 +1,107 @@
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 handler_exports = {};
28
+ __export(handler_exports, {
29
+ registerAIEmployeeTaskNotification: () => registerAIEmployeeTaskNotification,
30
+ registerOnJobAbortedHandler: () => registerOnJobAbortedHandler
31
+ });
32
+ module.exports = __toCommonJS(handler_exports);
33
+ var import_plugin_workflow = require("@nocobase/plugin-workflow");
34
+ const registerOnJobAbortedHandler = (plugin) => {
35
+ plugin.db.on("jobs.afterBulkUpdate", async (options) => {
36
+ const { model, attributes, where, transaction } = options;
37
+ if (attributes.status !== import_plugin_workflow.JOB_STATUS.ABORTED) {
38
+ return;
39
+ }
40
+ const jobs = await model.findAll({ where, transaction });
41
+ const aiWorkflowTasks = await plugin.db.getRepository("aiWorkflowTasks").find({
42
+ filter: {
43
+ jobId: jobs.map((it) => it.id)
44
+ },
45
+ transaction
46
+ });
47
+ if (!aiWorkflowTasks.length) {
48
+ return;
49
+ }
50
+ for (const aiWorkflowTask of aiWorkflowTasks) {
51
+ await plugin.db.getRepository("aiWorkflowTasks").update({
52
+ values: { status: "aborted" },
53
+ filter: {
54
+ id: aiWorkflowTask.id
55
+ },
56
+ transaction
57
+ });
58
+ }
59
+ });
60
+ };
61
+ const registerAIEmployeeTaskNotification = (plugin) => {
62
+ plugin.db.on("aiWorkflowTasks.beforeSave", async (model, options) => {
63
+ var _a;
64
+ if (!model.isNewRecord && !model.changed("status")) {
65
+ return;
66
+ }
67
+ const values = model.toJSON();
68
+ (_a = options.transaction) == null ? void 0 : _a.afterCommit(async () => {
69
+ const assignees = await plugin.db.getRepository("usersAiWorkflowTasks").find({
70
+ filter: {
71
+ aiWorkflowTaskId: values.id
72
+ }
73
+ });
74
+ if (!(assignees == null ? void 0 : assignees.length)) {
75
+ return;
76
+ }
77
+ if (values.status === "pending_acceptance") {
78
+ await plugin.db.getRepository("usersAiWorkflowTasks").update({
79
+ values: {
80
+ read: false
81
+ },
82
+ filter: {
83
+ aiWorkflowTaskId: values.id
84
+ }
85
+ });
86
+ }
87
+ for (const assignee of assignees) {
88
+ plugin.app.emit("ws:sendToUser", {
89
+ userId: assignee.userId,
90
+ message: {
91
+ type: "ai-employee-tasks:status",
92
+ payload: {
93
+ taskId: values.id,
94
+ sessionId: values.sessionId,
95
+ status: values.status
96
+ }
97
+ }
98
+ });
99
+ }
100
+ });
101
+ });
102
+ };
103
+ // Annotate the CommonJS export names for ESM import in node:
104
+ 0 && (module.exports = {
105
+ registerAIEmployeeTaskNotification,
106
+ registerOnJobAbortedHandler
107
+ });
@@ -0,0 +1,17 @@
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
+ import { FlowNodeModel, Instruction, Processor } from '@nocobase/plugin-workflow';
10
+ export declare class AIEmployeeInstruction extends Instruction {
11
+ run(node: FlowNodeModel, input: any, processor: Processor): Promise<void>;
12
+ resume(node: FlowNodeModel, job: any, processor: Processor): any;
13
+ private createWorkflowTask;
14
+ private checkApproval;
15
+ }
16
+ export * from './handler';
17
+ export * from './tools';
@@ -0,0 +1,391 @@
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 __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __export = (target, all) => {
17
+ for (var name in all)
18
+ __defProp(target, name, { get: all[name], enumerable: true });
19
+ };
20
+ var __copyProps = (to, from, except, desc) => {
21
+ if (from && typeof from === "object" || typeof from === "function") {
22
+ for (let key of __getOwnPropNames(from))
23
+ if (!__hasOwnProp.call(to, key) && key !== except)
24
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
25
+ }
26
+ return to;
27
+ };
28
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
29
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
30
+ // If the importer is in node compatibility mode or this is not an ESM
31
+ // file that has been converted to a CommonJS file using a Babel-
32
+ // compatible transform (i.e. "__esModule" has not been set), then set
33
+ // "default" to the CommonJS "module.exports" for node compatibility.
34
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
35
+ mod
36
+ ));
37
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
+ var employee_exports = {};
39
+ __export(employee_exports, {
40
+ AIEmployeeInstruction: () => AIEmployeeInstruction
41
+ });
42
+ module.exports = __toCommonJS(employee_exports);
43
+ var import_plugin_workflow = require("@nocobase/plugin-workflow");
44
+ var import_plugin = __toESM(require("../../../plugin"));
45
+ var import_ai_employee = require("../../../ai-employees/ai-employee");
46
+ var import_files = require("./files");
47
+ var import_utils = require("@nocobase/utils");
48
+ __reExport(employee_exports, require("./handler"), module.exports);
49
+ __reExport(employee_exports, require("./tools"), module.exports);
50
+ class AIEmployeeInstruction extends import_plugin_workflow.Instruction {
51
+ async run(node, input, processor) {
52
+ var _a, _b, _c, _d, _e;
53
+ const {
54
+ username,
55
+ message,
56
+ skillSettings,
57
+ webSearch,
58
+ model,
59
+ requiresApproval = "no_required",
60
+ userId,
61
+ files
62
+ } = processor.getParsedValue(node.config, node.id);
63
+ const toolName = "aiEmployeeWorkflowTaskOutput";
64
+ const workflowSystemPrompt = `
65
+ You are operating inside a workflow.
66
+ Your job is to complete the workflow task and return the final outcome to the workflow, not to reply freely as a normal assistant.
67
+ Use normal assistant messages only for reasoning that leads to tool calls; do not place the final outcome in a normal assistant message.
68
+ When the task is ready to be submitted, you must call **${toolName}** to return it to the workflow.
69
+ Do not treat **${toolName}** as optional, and do not finish the task without calling it.
70
+ `.trim();
71
+ const systemMessage = `${workflowSystemPrompt}
72
+
73
+ ${typeof message.system === "object" ? JSON.stringify(message.system) : message.system}`;
74
+ const userMessage = `Current workflow task description:
75
+
76
+ ${typeof message.user === "object" ? JSON.stringify(message.user) : message.user}`;
77
+ const { id } = processor.saveJob({
78
+ status: import_plugin_workflow.JOB_STATUS.PENDING,
79
+ nodeId: node.id,
80
+ nodeKey: node.key,
81
+ upstreamId: (input == null ? void 0 : input.id) ?? null
82
+ });
83
+ await processor.exit();
84
+ try {
85
+ const { conversation, aiWorkflowTasks } = await this.createWorkflowTask({
86
+ username,
87
+ userMessage,
88
+ systemMessage,
89
+ skillSettings,
90
+ requiresApproval,
91
+ toolName,
92
+ node,
93
+ processor,
94
+ jobId: id
95
+ });
96
+ let currentRoles = (_a = input == null ? void 0 : input.result) == null ? void 0 : _a.roleName;
97
+ if (!currentRoles) {
98
+ const defaultRole = await this.workflow.db.getRepository("rolesUsers").findOne({
99
+ filter: {
100
+ userId: ((_c = (_b = input == null ? void 0 : input.result) == null ? void 0 : _b.user) == null ? void 0 : _c.id) ?? userId,
101
+ default: true
102
+ }
103
+ });
104
+ currentRoles = defaultRole == null ? void 0 : defaultRole.roleName;
105
+ }
106
+ const employee = await this.workflow.db.getRepository("aiEmployees").findOne({
107
+ filter: {
108
+ username
109
+ }
110
+ });
111
+ const aiEmployee = new import_ai_employee.AIEmployee({
112
+ ctx: {
113
+ app: this.workflow.app,
114
+ db: this.workflow.app.db,
115
+ log: this.workflow.app.log,
116
+ logger: this.workflow.app.log,
117
+ state: { currentRoles },
118
+ auth: {
119
+ user: {
120
+ id: ((_e = (_d = input == null ? void 0 : input.result) == null ? void 0 : _d.user) == null ? void 0 : _e.id) ?? userId
121
+ }
122
+ },
123
+ action: {
124
+ params: {
125
+ values: {
126
+ sessionId: conversation.sessionId,
127
+ model
128
+ }
129
+ }
130
+ }
131
+ },
132
+ employee,
133
+ sessionId: conversation.sessionId,
134
+ systemMessage,
135
+ skillSettings,
136
+ webSearch,
137
+ model,
138
+ tools: [{ name: toolName }]
139
+ });
140
+ const attachmentPart = {};
141
+ if (files == null ? void 0 : files.length) {
142
+ const { resolveAttachments, resolveUrls } = import_files.Files.resolvers(this.workflow, attachmentPart);
143
+ await resolveAttachments(files);
144
+ await resolveUrls(files);
145
+ }
146
+ let result;
147
+ let isToolInvoke = false;
148
+ let retry = 0;
149
+ do {
150
+ const userMessages = [
151
+ {
152
+ role: "user",
153
+ content: {
154
+ type: "text",
155
+ content: userMessage
156
+ },
157
+ ...attachmentPart
158
+ }
159
+ ];
160
+ if (retry > 0) {
161
+ if (retry < 2) {
162
+ const firstUserMessage = await this.workflow.db.getRepository("aiConversations.messages", conversation.sessionId).findOne({
163
+ filter: {
164
+ role: "user"
165
+ },
166
+ sort: ["messageId"]
167
+ });
168
+ const messageId = firstUserMessage == null ? void 0 : firstUserMessage.messageId;
169
+ result = await aiEmployee.invoke({ messageId, userMessages });
170
+ } else {
171
+ result = await aiEmployee.invoke({
172
+ userMessages: [
173
+ {
174
+ role: "user",
175
+ content: {
176
+ type: "text",
177
+ content: `You failed to call the required tool "aiEmployeeWorkflowTaskOutput" in your previous response.
178
+ Call "aiEmployeeWorkflowTaskOutput" now to submit the workflow outcome.
179
+ Do not send another normal assistant response without invoking it.
180
+ `
181
+ }
182
+ }
183
+ ]
184
+ });
185
+ }
186
+ } else {
187
+ result = await aiEmployee.invoke({ userMessages });
188
+ }
189
+ isToolInvoke = result.messages.filter((it) => it.type === "ai").flatMap((it) => it.tool_calls).some((it) => it.name === toolName);
190
+ } while (!isToolInvoke && retry++ < 2);
191
+ if (!isToolInvoke) {
192
+ throw new Error("AI employee not do job correctly");
193
+ }
194
+ await this.checkApproval({ requiresApproval, conversation, aiWorkflowTasks, result, aiEmployee, toolName });
195
+ } catch (e) {
196
+ processor.logger.error(`ai employee invoke failed, ${e.message}`, {
197
+ node: node.id,
198
+ stack: e.stack,
199
+ chatOptions: node.config
200
+ });
201
+ const job = await this.workflow.app.db.getRepository("jobs").findOne({
202
+ filterByTk: id
203
+ });
204
+ job.set({
205
+ status: import_plugin_workflow.JOB_STATUS.ERROR,
206
+ result: e.message
207
+ });
208
+ await this.workflow.resume(job);
209
+ }
210
+ }
211
+ resume(node, job, processor) {
212
+ return job;
213
+ }
214
+ async createWorkflowTask({
215
+ username,
216
+ userMessage,
217
+ systemMessage,
218
+ skillSettings,
219
+ requiresApproval,
220
+ toolName,
221
+ node,
222
+ processor,
223
+ jobId
224
+ }) {
225
+ const ai = this.workflow.app.pm.get(import_plugin.default);
226
+ return await this.workflow.db.sequelize.transaction(async (transaction) => {
227
+ var _a;
228
+ const conversation = await ai.aiConversationsManager.create({
229
+ aiEmployee: {
230
+ username
231
+ },
232
+ title: userMessage.slice(0, 30),
233
+ from: "sub-agent",
234
+ options: {
235
+ systemMessage,
236
+ skillSettings,
237
+ tools: [{ name: toolName }]
238
+ },
239
+ transaction,
240
+ category: "task"
241
+ });
242
+ const aiWorkflowTasks = await this.workflow.db.getRepository("aiWorkflowTasks").create({
243
+ values: {
244
+ id: this.workflow.app.snowflakeIdGenerator.generate(),
245
+ workflowTitle: (_a = processor.execution.workflow) == null ? void 0 : _a.title,
246
+ nodeTitle: node.title,
247
+ requiresApproval,
248
+ status: "processing",
249
+ sessionId: conversation.sessionId,
250
+ jobId,
251
+ executionId: processor.execution.id,
252
+ nodeId: node.id,
253
+ workflowId: node.workflowId
254
+ },
255
+ transaction
256
+ });
257
+ const userIds = await parseAssignees(node, processor);
258
+ if (userIds == null ? void 0 : userIds.length) {
259
+ await this.workflow.db.getRepository("usersAiWorkflowTasks").create({
260
+ values: userIds.map((userId) => ({
261
+ userId,
262
+ aiWorkflowTaskId: aiWorkflowTasks.id,
263
+ read: true
264
+ })),
265
+ transaction
266
+ });
267
+ }
268
+ return { conversation, aiWorkflowTasks };
269
+ });
270
+ }
271
+ async checkApproval({
272
+ requiresApproval,
273
+ conversation,
274
+ aiWorkflowTasks,
275
+ result,
276
+ aiEmployee,
277
+ toolName
278
+ }) {
279
+ var _a;
280
+ const ai = this.workflow.app.pm.get(import_plugin.default);
281
+ const aiToolMessage = await this.workflow.db.getRepository("aiToolMessages").findOne({
282
+ filter: {
283
+ sessionId: conversation.sessionId,
284
+ messageId: result.messageId
285
+ }
286
+ });
287
+ if ((aiToolMessage == null ? void 0 : aiToolMessage.invokeStatus) !== "interrupted") {
288
+ return;
289
+ }
290
+ const aiMessage = await this.workflow.db.getRepository("aiMessages").findOne({
291
+ filter: {
292
+ messageId: result.messageId
293
+ }
294
+ });
295
+ const toolCalls = aiMessage == null ? void 0 : aiMessage.toolCalls;
296
+ if (!(toolCalls == null ? void 0 : toolCalls.length)) {
297
+ return;
298
+ }
299
+ const toolCall = toolCalls.find((it) => it.name === toolName);
300
+ if (((_a = toolCall == null ? void 0 : toolCall.args) == null ? void 0 : _a.requiresApproval) === false) {
301
+ const [updated] = await this.workflow.db.getModel("aiToolMessages").update(
302
+ { userDecision: { type: "approve" }, invokeStatus: "waiting" },
303
+ {
304
+ where: {
305
+ sessionId: conversation.sessionId,
306
+ messageId: result.messageId,
307
+ invokeStatus: "interrupted"
308
+ }
309
+ }
310
+ );
311
+ if (!updated) {
312
+ return;
313
+ }
314
+ const userDecisions = await ai.aiConversationsManager.getUserDecisions(result.messageId);
315
+ await aiEmployee.invoke({ userDecisions });
316
+ await this.workflow.db.getRepository("aiWorkflowTasks").update({
317
+ values: { status: "approved" },
318
+ filter: {
319
+ id: aiWorkflowTasks.id,
320
+ status: {
321
+ $ne: "aborted"
322
+ }
323
+ }
324
+ });
325
+ } else if (requiresApproval !== "no_required") {
326
+ await this.workflow.db.getRepository("aiWorkflowTasks").update({
327
+ values: { status: "pending_acceptance" },
328
+ filter: {
329
+ id: aiWorkflowTasks.id,
330
+ status: {
331
+ $ne: "aborted"
332
+ }
333
+ }
334
+ });
335
+ }
336
+ }
337
+ }
338
+ async function parseAssignees(node, processor) {
339
+ const configAssignees = processor.getParsedValue(node.config.assignees ?? [], node.id).flat().filter(Boolean);
340
+ const assignees = [];
341
+ const seen = /* @__PURE__ */ new Set();
342
+ const addAssignee = (id) => {
343
+ if (!seen.has(id)) {
344
+ seen.add(id);
345
+ assignees.push(id);
346
+ }
347
+ };
348
+ const UserRepo = processor.options.plugin.app.db.getRepository("users");
349
+ const plainIds = configAssignees.flatMap(
350
+ (item) => Array.isArray(item) ? item : typeof item !== "object" ? [item] : []
351
+ );
352
+ const validIdSet = /* @__PURE__ */ new Set();
353
+ if (plainIds.length) {
354
+ const users = await UserRepo.find({
355
+ filter: { id: { $in: plainIds } },
356
+ fields: ["id"],
357
+ transaction: processor.mainTransaction
358
+ });
359
+ users.forEach((u) => validIdSet.add(u.id));
360
+ }
361
+ for (const item of configAssignees) {
362
+ if (Array.isArray(item)) {
363
+ for (const id of item) {
364
+ if (validIdSet.has(id)) {
365
+ addAssignee(id);
366
+ }
367
+ }
368
+ } else if (typeof item === "object") {
369
+ if (!(0, import_utils.isValidFilter)(item.filter)) {
370
+ continue;
371
+ }
372
+ const result = await UserRepo.find({
373
+ ...item,
374
+ fields: ["id"],
375
+ transaction: processor.mainTransaction
376
+ });
377
+ result.forEach((user) => addAssignee(user.id));
378
+ } else {
379
+ if (validIdSet.has(item)) {
380
+ addAssignee(item);
381
+ }
382
+ }
383
+ }
384
+ return assignees;
385
+ }
386
+ // Annotate the CommonJS export names for ESM import in node:
387
+ 0 && (module.exports = {
388
+ AIEmployeeInstruction,
389
+ ...require("./handler"),
390
+ ...require("./tools")
391
+ });
@@ -0,0 +1,12 @@
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
+ import { DynamicToolsProvider } from '@nocobase/ai';
10
+ import { Plugin } from '@nocobase/server';
11
+ export type WorkflowTaskToolProvider = (plugin: Plugin) => DynamicToolsProvider;
12
+ export declare const getWorkflowTasks: WorkflowTaskToolProvider;
@@ -0,0 +1,133 @@
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 tools_exports = {};
28
+ __export(tools_exports, {
29
+ getWorkflowTasks: () => getWorkflowTasks
30
+ });
31
+ module.exports = __toCommonJS(tools_exports);
32
+ var import_plugin_workflow = require("@nocobase/plugin-workflow");
33
+ const getWorkflowTasks = (plugin) => async (register, filter) => {
34
+ if (!(filter == null ? void 0 : filter.sessionId)) {
35
+ return;
36
+ }
37
+ const workflowPlugin = plugin.app.pm.get("workflow");
38
+ const task = await plugin.db.getRepository("aiWorkflowTasks").findOne({
39
+ filter: {
40
+ sessionId: filter == null ? void 0 : filter.sessionId
41
+ }
42
+ });
43
+ if (!task) {
44
+ return;
45
+ }
46
+ const execution = await plugin.db.getRepository("executions").findByTargetKey(task.executionId);
47
+ if (!execution) {
48
+ return;
49
+ }
50
+ const flowNode = await plugin.db.getRepository("flow_nodes").findByTargetKey(task.nodeId);
51
+ if (!flowNode) {
52
+ return;
53
+ }
54
+ const processor = workflowPlugin.createProcessor(execution);
55
+ const config = processor.getParsedValue(flowNode.config, flowNode.id);
56
+ const outputSchema = config.structuredOutput.schema;
57
+ const parsedOutputSchema = typeof outputSchema === "string" ? JSON.parse(outputSchema) : outputSchema;
58
+ const resultSchema = parsedOutputSchema && typeof parsedOutputSchema === "object" && !Array.isArray(parsedOutputSchema) ? {
59
+ ...parsedOutputSchema,
60
+ description: parsedOutputSchema.description || `Return the final structured output for this workflow task in this field.
61
+ The value must match the required schema exactly so the workflow can continue.
62
+ Do not include free-form text, extra fields, or any structure outside the defined schema.`
63
+ } : parsedOutputSchema;
64
+ const schema = {
65
+ type: "object",
66
+ properties: {
67
+ result: resultSchema
68
+ },
69
+ additionalProperties: false
70
+ };
71
+ if (config.requiresApproval === "ai_decision") {
72
+ schema.properties.requiresApproval = {
73
+ type: "boolean",
74
+ description: `This field is mandatory.
75
+ Set it to true whenever the human user still needs to review the result, confirm it, make a decision,
76
+ provide missing information, answer your follow-up questions, or correct the result.
77
+ Set it to false only when you have determined that the task is fully complete, the result you are returning fully satisfies the required schema and the task requirements,
78
+ and no human user needs to review the result or provide any additional information before the workflow continues.
79
+ Warning: if requiresApproval=false, this AI workflow node ends immediately, the workflow moves to the next node,
80
+ and the human will no longer be able to continue this conversation with the AI.
81
+ If a human may still need to say anything else, do not set it to false.`
82
+ };
83
+ }
84
+ register.registerTools({
85
+ scope: "SPECIFIED",
86
+ defaultPermission: config.requiresApproval !== "no_required" ? "ASK" : "ALLOW",
87
+ from: "workflow",
88
+ definition: {
89
+ name: "aiEmployeeWorkflowTaskOutput",
90
+ description: `Use this tool to return the structured output required by the workflow so execution can continue.
91
+ Every time you call it, you must provide the final data strictly under result and match the result schema exactly.
92
+ Do not return free-form text, extra fields, or any structure outside the defined result.`,
93
+ schema
94
+ },
95
+ invoke: async (_ctx, args) => {
96
+ const job = await plugin.db.getModel("jobs").findByPk(task.jobId);
97
+ if (!job) {
98
+ return {
99
+ status: "fail",
100
+ message: "job not existed"
101
+ };
102
+ }
103
+ if (job.status === import_plugin_workflow.JOB_STATUS.ABORTED) {
104
+ return {
105
+ status: "success"
106
+ };
107
+ }
108
+ await plugin.db.getRepository("aiWorkflowTasks").update({
109
+ values: {
110
+ status: "approved"
111
+ },
112
+ filter: {
113
+ id: task.id,
114
+ status: {
115
+ $ne: "aborted"
116
+ }
117
+ }
118
+ });
119
+ job.set({
120
+ status: import_plugin_workflow.JOB_STATUS.RESOLVED,
121
+ result: args.result
122
+ });
123
+ await workflowPlugin.resume(job);
124
+ return {
125
+ status: "success"
126
+ };
127
+ }
128
+ });
129
+ };
130
+ // Annotate the CommonJS export names for ESM import in node:
131
+ 0 && (module.exports = {
132
+ getWorkflowTasks
133
+ });
@@ -0,0 +1,35 @@
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
+ export type AIEmployeeInstructionConfig = {
10
+ username: string;
11
+ message: {
12
+ user: string;
13
+ system?: string;
14
+ };
15
+ skillSettings?: {
16
+ skills?: string[];
17
+ tools?: {
18
+ name: string;
19
+ }[];
20
+ };
21
+ webSearch?: boolean;
22
+ model: {
23
+ llmService: string;
24
+ model: string;
25
+ };
26
+ requiresApproval?: 'no_required' | 'ai_decision' | 'human_decision';
27
+ assignees?: string[];
28
+ userId: string;
29
+ files: AIEmployeeInstructionFiles[];
30
+ };
31
+ export type AIEmployeeInstructionFiles = {
32
+ type: 'file_id' | 'file_url';
33
+ collection?: string;
34
+ value: string;
35
+ };