@nocobase/plugin-ai 2.1.0-alpha.13 → 2.1.0-alpha.15

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/dist/ai/ai-employees/atlas/index.d.ts +10 -0
  2. package/dist/ai/ai-employees/atlas/index.js +56 -0
  3. package/dist/ai/ai-employees/atlas/prompt.md +84 -0
  4. package/dist/ai/ai-employees/vera.js +1 -1
  5. package/dist/ai/skills/business-analysis-report/SKILLS.md +84 -0
  6. package/dist/ai/tools/businessReportGenerator.d.ts +10 -0
  7. package/dist/ai/tools/businessReportGenerator.js +83 -0
  8. package/dist/ai/tools/chartGenerator.js +1 -0
  9. package/dist/ai/tools/getSkill.js +1 -1
  10. package/dist/ai/tools/sub-agents/dispatch-sub-agent-task.d.ts +10 -0
  11. package/dist/ai/tools/sub-agents/dispatch-sub-agent-task.js +108 -0
  12. package/dist/ai/tools/sub-agents/get-ai-employee.d.ts +10 -0
  13. package/dist/ai/tools/sub-agents/get-ai-employee.js +67 -0
  14. package/dist/ai/tools/sub-agents/list-ai-employees.d.ts +10 -0
  15. package/dist/ai/tools/sub-agents/list-ai-employees.js +64 -0
  16. package/dist/ai/tools/sub-agents/shared.d.ts +33 -0
  17. package/dist/ai/tools/sub-agents/shared.js +169 -0
  18. package/dist/ai/tools/subAgentWebSearch.d.ts +10 -0
  19. package/dist/ai/tools/subAgentWebSearch.js +103 -0
  20. package/dist/ai/tools/suggestions.js +2 -2
  21. package/dist/client/0e94d90f0134df30.js +10 -0
  22. package/dist/client/{4f9117811ffc7ab3.js → 1c3ef55a6d63c9a3.js} +1 -1
  23. package/dist/client/55d67b74f02b8d74.js +10 -0
  24. package/dist/client/{6dc8c9b641452067.js → 5d5c118d11e91913.js} +1 -1
  25. package/dist/client/748fbb87c1013c6e.js +10 -0
  26. package/dist/client/8e82080c5e8ccfb7.js +10 -0
  27. package/dist/client/a8d6d81fb88f1a8e.js +10 -0
  28. package/dist/client/ai-employees/built-in/utils.d.ts +1 -0
  29. package/dist/client/ai-employees/business-report/tools/index.d.ts +10 -0
  30. package/dist/client/ai-employees/business-report/ui/BusinessReportCard.d.ts +12 -0
  31. package/dist/client/ai-employees/business-report/ui/BusinessReportModal.d.ts +17 -0
  32. package/dist/client/ai-employees/business-report/ui/report-utils.d.ts +36 -0
  33. package/dist/client/ai-employees/chatbox/AIEmployeeSwitch.d.ts +0 -1
  34. package/dist/client/ai-employees/chatbox/hooks/useChatBoxActions.d.ts +5 -3
  35. package/dist/client/ai-employees/chatbox/markdown/ECharts.d.ts +1 -2
  36. package/dist/client/ai-employees/chatbox/markdown/Markdown.d.ts +1 -1
  37. package/dist/client/ai-employees/chatbox/roles.d.ts +1 -0
  38. package/dist/client/ai-employees/chatbox/stores/chat-messages.d.ts +8 -0
  39. package/dist/client/ai-employees/chatbox/utils.d.ts +15 -1
  40. package/dist/client/ai-employees/sub-agents/tools/index.d.ts +10 -0
  41. package/dist/client/ai-employees/sub-agents/ui/SubAgentDispatchCard.d.ts +21 -0
  42. package/dist/client/ai-employees/types.d.ts +19 -0
  43. package/dist/client/c065565ccbb41f99.js +10 -0
  44. package/dist/client/d5e9663991c30eed.js +10 -0
  45. package/dist/client/f87cff5213f94856.js +10 -0
  46. package/dist/client/f8c075896e8b9c0b.js +10 -0
  47. package/dist/client/fd4e5dcaf24052c1.js +10 -0
  48. package/dist/client/index.js +7 -7
  49. package/dist/client/manager/ai-manager.d.ts +4 -23
  50. package/dist/externalVersion.js +17 -15
  51. package/dist/locale/en-US.json +30 -1
  52. package/dist/locale/zh-CN.json +30 -1
  53. package/dist/node_modules/fast-glob/package.json +1 -1
  54. package/dist/node_modules/flexsearch/package.json +1 -1
  55. package/dist/node_modules/fs-extra/package.json +1 -1
  56. package/dist/node_modules/nodejs-snowflake/package.json +1 -1
  57. package/dist/node_modules/openai/package.json +1 -1
  58. package/dist/node_modules/zod/package.json +1 -1
  59. package/dist/server/ai-employees/ai-conversations.d.ts +64 -0
  60. package/dist/server/ai-employees/ai-conversations.js +285 -0
  61. package/dist/server/ai-employees/ai-employee.d.ts +88 -14
  62. package/dist/server/ai-employees/ai-employee.js +335 -200
  63. package/dist/server/ai-employees/middleware/conversation.d.ts +2 -0
  64. package/dist/server/ai-employees/middleware/conversation.js +38 -5
  65. package/dist/server/ai-employees/middleware/tools.js +37 -10
  66. package/dist/server/ai-employees/prompts.d.ts +11 -1
  67. package/dist/server/ai-employees/prompts.js +29 -2
  68. package/dist/server/ai-employees/sub-agents/dispatcher.d.ts +36 -0
  69. package/dist/server/ai-employees/sub-agents/dispatcher.js +225 -0
  70. package/dist/server/ai-employees/sub-agents/index.d.ts +9 -0
  71. package/dist/server/ai-employees/sub-agents/index.js +36 -0
  72. package/dist/server/ai-employees/utils.js +1 -1
  73. package/dist/server/collections/ai-conversations.js +6 -0
  74. package/dist/server/llm-providers/anthropic.d.ts +1 -0
  75. package/dist/server/llm-providers/anthropic.js +2 -1
  76. package/dist/server/llm-providers/dashscope.d.ts +3 -0
  77. package/dist/server/llm-providers/dashscope.js +13 -1
  78. package/dist/server/llm-providers/deepseek.d.ts +1 -0
  79. package/dist/server/llm-providers/deepseek.js +5 -2
  80. package/dist/server/llm-providers/google-genai.d.ts +1 -0
  81. package/dist/server/llm-providers/google-genai.js +2 -1
  82. package/dist/server/llm-providers/kimi/provider.d.ts +1 -0
  83. package/dist/server/llm-providers/openai/responses.d.ts +1 -0
  84. package/dist/server/llm-providers/openai/responses.js +2 -1
  85. package/dist/server/llm-providers/provider.d.ts +1 -10
  86. package/dist/server/llm-providers/provider.js +3 -34
  87. package/dist/server/manager/ai-manager.d.ts +10 -0
  88. package/dist/server/manager/ai-manager.js +32 -0
  89. package/dist/server/migrations/20260319000000-add-ai-conversations-from.d.ts +14 -0
  90. package/dist/server/migrations/20260319000000-add-ai-conversations-from.js +63 -0
  91. package/dist/server/plugin.d.ts +4 -0
  92. package/dist/server/plugin.js +4 -0
  93. package/dist/server/resource/aiConversations.d.ts +3 -3
  94. package/dist/server/resource/aiConversations.js +125 -159
  95. package/dist/server/types/ai-chat-conversation.type.d.ts +8 -2
  96. package/dist/server/types/ai-message.type.d.ts +7 -0
  97. package/dist/server/utils.d.ts +3 -0
  98. package/dist/server/utils.js +28 -1
  99. package/package.json +4 -2
  100. package/dist/client/27539a4356faebb1.js +0 -10
  101. package/dist/client/39492c2121f4c722.js +0 -10
  102. package/dist/client/53190ab4290ef9d5.js +0 -10
  103. package/dist/client/9c00efb8eb0b4d69.js +0 -10
  104. package/dist/client/d4e2ed9fa44a82b2.js +0 -10
@@ -36,11 +36,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
36
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
37
37
  var ai_employee_exports = {};
38
38
  __export(ai_employee_exports, {
39
- AIEmployee: () => AIEmployee
39
+ AIEmployee: () => AIEmployee,
40
+ ChatStreamProtocol: () => ChatStreamProtocol
40
41
  });
41
42
  module.exports = __toCommonJS(ai_employee_exports);
42
43
  var import_database = require("@nocobase/database");
43
- var import_provider = require("../llm-providers/provider");
44
44
  var import_utils = require("../utils");
45
45
  var import_prompts = require("./prompts");
46
46
  var import_lodash = __toESM(require("lodash"));
@@ -54,20 +54,32 @@ var import_langgraph = require("@langchain/langgraph");
54
54
  var import_stream = require("@langchain/core/utils/stream");
55
55
  var import_utils2 = require("./utils");
56
56
  var import_base = require("@langchain/core/callbacks/base");
57
+ var import_shared = require("../../ai/tools/sub-agents/shared");
57
58
  class AIEmployee {
59
+ sessionId;
60
+ from = "main-agent";
58
61
  employee;
59
62
  aiChatConversation;
60
63
  skillSettings;
61
64
  plugin;
62
65
  db;
63
- sessionId;
64
66
  ctx;
65
67
  systemMessage;
68
+ protocol;
66
69
  webSearch;
67
70
  model;
68
71
  legacy;
69
- protocol;
70
- constructor(ctx, employee, sessionId, systemMessage, skillSettings, webSearch, model, legacy) {
72
+ constructor({
73
+ ctx,
74
+ employee,
75
+ sessionId,
76
+ systemMessage,
77
+ skillSettings,
78
+ webSearch,
79
+ model,
80
+ legacy,
81
+ from = "main-agent"
82
+ }) {
71
83
  this.employee = employee;
72
84
  this.ctx = ctx;
73
85
  this.plugin = ctx.app.pm.get("ai");
@@ -78,10 +90,21 @@ class AIEmployee {
78
90
  this.skillSettings = skillSettings;
79
91
  this.model = model;
80
92
  this.legacy = legacy;
93
+ this.from = from;
81
94
  const builtInManager = this.plugin.builtInManager;
82
95
  builtInManager.setupBuiltInInfo(ctx, this.employee);
83
96
  this.webSearch = webSearch;
84
- this.protocol = ChatStreamProtocol.create(ctx);
97
+ this.protocol = ChatStreamProtocol.fromContext(ctx);
98
+ }
99
+ async getFormatMessages(userMessages) {
100
+ const { provider } = await this.plugin.aiManager.getLLMService({
101
+ ...this.model
102
+ });
103
+ const { messages } = await this.aiChatConversation.getChatContext({
104
+ userMessages,
105
+ formatMessages: (messages2) => this.formatMessages({ messages: messages2, provider })
106
+ });
107
+ return messages;
85
108
  }
86
109
  // === Chat flow ===
87
110
  buildState(messages) {
@@ -133,7 +156,9 @@ class AIEmployee {
133
156
  userMessages,
134
157
  userDecisions
135
158
  }) {
136
- const { provider, model, service } = await this.getLLMService();
159
+ const { provider, model, service } = await this.plugin.aiManager.getLLMService({
160
+ ...this.model
161
+ });
137
162
  const { historyMessages, tools, middleware, config, state } = await this.initSession({
138
163
  messageId,
139
164
  provider,
@@ -186,7 +211,9 @@ class AIEmployee {
186
211
  async invoke({
187
212
  messageId,
188
213
  userMessages = [],
189
- userDecisions
214
+ userDecisions,
215
+ writer,
216
+ context
190
217
  }) {
191
218
  try {
192
219
  const { provider, chatContext, config, state } = await this.buildChatContext({
@@ -194,54 +221,25 @@ class AIEmployee {
194
221
  userMessages,
195
222
  userDecisions
196
223
  });
197
- const { threadId } = await this.getCurrentThread();
198
224
  const invokeConfig = {
199
- configurable: { thread_id: threadId },
200
- context: { ctx: this.ctx },
225
+ context: { ctx: this.ctx, decisions: chatContext.decisions, ...context },
201
226
  recursionLimit: 100,
227
+ writer,
202
228
  ...config
203
229
  };
230
+ if (this.from === "main-agent") {
231
+ const { threadId } = await this.getCurrentThread();
232
+ invokeConfig.configurable = { thread_id: threadId };
233
+ }
204
234
  return await this.agentInvoke(provider, chatContext, invokeConfig, state);
205
235
  } catch (err) {
236
+ if (err.name === "GraphInterrupt") {
237
+ throw err;
238
+ }
206
239
  this.ctx.log.error(err);
207
240
  throw err;
208
241
  }
209
242
  }
210
- // === LLM/provider setup ===
211
- async getLLMService() {
212
- var _a, _b;
213
- if (!((_a = this.model) == null ? void 0 : _a.llmService) || !((_b = this.model) == null ? void 0 : _b.model)) {
214
- throw new Error("LLM service not configured");
215
- }
216
- const llmServiceName = this.model.llmService;
217
- const model = this.model.model;
218
- const modelOptions = {
219
- llmService: llmServiceName,
220
- model
221
- };
222
- if (this.webSearch === true) {
223
- modelOptions.builtIn = { webSearch: true };
224
- }
225
- const service = await this.db.getRepository("llmServices").findOne({
226
- filter: {
227
- name: llmServiceName
228
- }
229
- });
230
- if (!service) {
231
- throw new Error("LLM service not found");
232
- }
233
- const providerOptions = this.plugin.aiManager.llmProviders.get(service.provider);
234
- if (!providerOptions) {
235
- throw new Error("LLM service provider not found");
236
- }
237
- const Provider = providerOptions.provider;
238
- const provider = new Provider({
239
- app: this.ctx.app,
240
- serviceOptions: service.options,
241
- modelOptions
242
- });
243
- return { provider, model, service };
244
- }
245
243
  // === Agent wiring & execution ===
246
244
  async createAgent({
247
245
  provider,
@@ -250,17 +248,24 @@ class AIEmployee {
250
248
  middleware
251
249
  }) {
252
250
  const model = provider.createModel();
253
- const toolDefinitions = (tools == null ? void 0 : tools.map(import_provider.ToolDefinition.from("ToolsEntry"))) ?? [];
254
- const allTools = provider.resolveTools(toolDefinitions);
255
- const checkpointer = new import_checkpoints.SequelizeCollectionSaver(() => this.ctx.app.mainDataSource);
256
- return (0, import_langchain.createAgent)({ model, tools: allTools, middleware, systemPrompt, checkpointer });
251
+ const allTools = provider.resolveTools((tools == null ? void 0 : tools.map(import_utils.buildTool)) ?? []);
252
+ if (this.from === "main-agent") {
253
+ const checkpointer = new import_checkpoints.SequelizeCollectionSaver(() => this.ctx.app.mainDataSource);
254
+ return (0, import_langchain.createAgent)({ model, tools: allTools, middleware, systemPrompt, checkpointer });
255
+ } else {
256
+ return (0, import_langchain.createAgent)({ model, tools: allTools, middleware, systemPrompt });
257
+ }
257
258
  }
258
259
  getAgentInput(context, state) {
259
- var _a;
260
- if ((_a = context.decisions) == null ? void 0 : _a.length) {
260
+ var _a, _b;
261
+ if ((_b = (_a = context.decisions) == null ? void 0 : _a.decisions) == null ? void 0 : _b.length) {
261
262
  return new import_langgraph.Command({
262
- resume: {
263
- decisions: context.decisions
263
+ resume: context.decisions.interruptId ? {
264
+ [context.decisions.interruptId]: {
265
+ decisions: context.decisions.decisions
266
+ }
267
+ } : {
268
+ decisions: context.decisions.decisions
264
269
  }
265
270
  });
266
271
  }
@@ -273,13 +278,16 @@ class AIEmployee {
273
278
  const { systemPrompt, tools, middleware } = context;
274
279
  const agent = await this.createAgent({ provider, systemPrompt, tools, middleware });
275
280
  const input = this.getAgentInput(context, state);
276
- return agent.stream(input, config);
281
+ if (this.from === "sub-agent") {
282
+ delete config.configurable;
283
+ }
284
+ return agent.stream(input, this.withRunMetadata(config));
277
285
  }
278
286
  async agentInvoke(provider, context, config, state) {
279
287
  const { systemPrompt, tools, middleware } = context;
280
288
  const agent = await this.createAgent({ provider, systemPrompt, tools, middleware });
281
289
  const input = this.getAgentInput(context, state);
282
- return agent.invoke(input, config);
290
+ return agent.invoke(input, this.withRunMetadata(config));
283
291
  }
284
292
  async prepareChatStream({
285
293
  chatContext,
@@ -297,8 +305,8 @@ class AIEmployee {
297
305
  {
298
306
  signal,
299
307
  streamMode: ["updates", "messages", "custom"],
300
- configurable: { thread_id: threadId },
301
- context: { ctx: this.ctx },
308
+ configurable: this.from === "main-agent" ? { thread_id: threadId } : void 0,
309
+ context: { ctx: this.ctx, decisions: chatContext.decisions },
302
310
  recursionLimit: 100,
303
311
  ...config
304
312
  },
@@ -311,76 +319,91 @@ class AIEmployee {
311
319
  }
312
320
  }
313
321
  async processChatStream(stream, options) {
314
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
315
- let toolCalls;
322
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
323
+ const aiMessageIdMap = /* @__PURE__ */ new Map();
316
324
  const { signal, providerName, model, provider, responseMetadata, allowEmpty = false } = options;
317
325
  let isReasoning = false;
318
326
  let gathered;
319
327
  signal.addEventListener("abort", async () => {
320
- if ((gathered == null ? void 0 : gathered.type) === "ai") {
321
- const values = (0, import_utils2.convertAIMessage)({
322
- aiEmployee: this,
323
- providerName,
324
- model,
325
- aiMessage: gathered
326
- });
327
- if (values) {
328
- values.metadata.interrupted = true;
329
- }
330
- await this.aiChatConversation.withTransaction(async (conversation, transaction) => {
331
- const result = await conversation.addMessages(values);
332
- if (toolCalls == null ? void 0 : toolCalls.length) {
333
- await this.initToolCall(transaction, result.messageId, toolCalls);
328
+ try {
329
+ if ((gathered == null ? void 0 : gathered.type) === "ai") {
330
+ const values = (0, import_utils2.convertAIMessage)({
331
+ aiEmployee: this,
332
+ providerName,
333
+ model,
334
+ aiMessage: gathered
335
+ });
336
+ if (values) {
337
+ values.metadata.interrupted = true;
334
338
  }
335
- });
339
+ await this.aiChatConversation.withTransaction(async (conversation, transaction) => {
340
+ const result = await conversation.addMessages(values);
341
+ });
342
+ }
343
+ } catch (e) {
344
+ this.logger.error("Fail to save message after conversation abort", gathered);
336
345
  }
337
346
  });
338
347
  try {
339
- this.protocol.startStream();
348
+ const aiEmployeeConversation = {
349
+ sessionId: this.sessionId,
350
+ from: this.from,
351
+ username: this.employee.username
352
+ };
353
+ this.protocol.with(aiEmployeeConversation).startStream();
340
354
  for await (const [mode, chunks] of stream) {
341
355
  if (mode === "messages") {
342
- const [chunk] = chunks;
356
+ const [chunk, metadata] = chunks;
357
+ const { currentConversation } = metadata;
343
358
  if (chunk.type === "ai") {
344
359
  gathered = gathered !== void 0 ? (0, import_stream.concat)(gathered, chunk) : chunk;
345
360
  if (chunk.content) {
346
361
  if (isReasoning) {
347
362
  isReasoning = false;
348
- this.protocol.stopReasoning();
363
+ this.protocol.with(currentConversation).stopReasoning();
349
364
  }
350
365
  const parsedContent = provider.parseResponseChunk(chunk.content);
351
366
  if (parsedContent) {
352
- this.protocol.content(parsedContent);
367
+ this.protocol.with(currentConversation).content(parsedContent);
353
368
  }
354
369
  }
355
370
  if ((_a = chunk.tool_call_chunks) == null ? void 0 : _a.length) {
356
- this.protocol.toolCallChunks(chunk.tool_call_chunks);
371
+ this.protocol.with(currentConversation).toolCallChunks(chunk.tool_call_chunks);
357
372
  }
358
373
  const webSearch = provider.parseWebSearchAction(chunk);
359
374
  if (webSearch == null ? void 0 : webSearch.length) {
360
- this.protocol.webSearch(webSearch);
375
+ this.protocol.with(currentConversation).webSearch(webSearch);
361
376
  }
362
377
  const reasoningContent = provider.parseReasoningContent(chunk);
363
378
  if (reasoningContent) {
364
379
  isReasoning = true;
365
- this.protocol.reasoning(reasoningContent);
380
+ this.protocol.with(currentConversation).reasoning(reasoningContent);
366
381
  }
367
382
  }
368
383
  } else if (mode === "updates") {
369
384
  if ("__interrupt__" in chunks) {
385
+ const interruptId = chunks.__interrupt__[0].id;
370
386
  const interruptActions = this.toInterruptActions(chunks.__interrupt__[0].value);
371
387
  if (interruptActions.size) {
372
- for (const toolCall of toolCalls ?? []) {
373
- const interruptAction = interruptActions.get(toolCall.name);
374
- if (!interruptAction) {
388
+ const toolsMap = await this.getToolsMap();
389
+ for (const interruptAction of interruptActions.values()) {
390
+ if (!interruptAction.currentConversation || !interruptAction.toolCall) {
391
+ this.logger.warn("currentConversation or toolCall not exist in __interrupt__", interruptAction);
375
392
  continue;
376
393
  }
377
- await this.updateToolCallInterrupted(toolCall.messageId, toolCall.id, interruptAction);
378
- this.protocol.toolCallStatus({
394
+ const { sessionId, from, username } = interruptAction.currentConversation;
395
+ const { id: toolCallId, name: toolCallName } = interruptAction.toolCall;
396
+ const messageId = aiMessageIdMap.get(sessionId);
397
+ if (!messageId) {
398
+ continue;
399
+ }
400
+ await this.updateToolCallInterrupted(sessionId, messageId, toolCallId, interruptId, interruptAction);
401
+ this.protocol.with(interruptAction.currentConversation).toolCallStatus({
379
402
  toolCall: {
380
- messageId: toolCall.messageId,
381
- id: toolCall.id,
382
- name: toolCall.name,
383
- willInterrupt: toolCall.willInterrupt
403
+ messageId,
404
+ id: toolCallId,
405
+ name: toolCallName,
406
+ willInterrupt: this.shouldInterruptToolCall(toolsMap.get(toolCallName))
384
407
  },
385
408
  invokeStatus: "interrupted",
386
409
  interruptAction
@@ -389,7 +412,9 @@ class AIEmployee {
389
412
  }
390
413
  }
391
414
  } else if (mode === "custom") {
415
+ const { currentConversation } = chunks;
392
416
  if (chunks.action === "AfterAIMessageSaved") {
417
+ aiMessageIdMap.set(currentConversation.sessionId, chunks.body.messageId);
393
418
  const data = responseMetadata.get(chunks.body.id);
394
419
  if (data) {
395
420
  const savedMessage = await this.aiMessagesModel.findOne({
@@ -417,32 +442,34 @@ class AIEmployee {
417
442
  }
418
443
  }
419
444
  } else if (chunks.action === "initToolCalls") {
420
- toolCalls = ((_b = chunks.body) == null ? void 0 : _b.toolCalls) ?? [];
421
- this.protocol.toolCalls(chunks.body);
445
+ this.protocol.with(currentConversation).toolCalls(chunks.body);
422
446
  } else if (chunks.action === "beforeToolCall") {
423
447
  const toolsMap = await this.getToolsMap();
424
- const willInterrupt = this.shouldInterruptToolCall(toolsMap.get((_d = (_c = chunks.body) == null ? void 0 : _c.toolCall) == null ? void 0 : _d.name));
425
- this.protocol.toolCallStatus({
448
+ const willInterrupt = this.shouldInterruptToolCall(toolsMap.get((_c = (_b = chunks.body) == null ? void 0 : _b.toolCall) == null ? void 0 : _c.name));
449
+ this.protocol.with(currentConversation).toolCallStatus({
426
450
  toolCall: {
427
- messageId: (_f = (_e = chunks.body) == null ? void 0 : _e.toolCall) == null ? void 0 : _f.messageId,
428
- id: (_h = (_g = chunks.body) == null ? void 0 : _g.toolCall) == null ? void 0 : _h.id,
429
- name: (_j = (_i = chunks.body) == null ? void 0 : _i.toolCall) == null ? void 0 : _j.name,
451
+ messageId: (_e = (_d = chunks.body) == null ? void 0 : _d.toolCall) == null ? void 0 : _e.messageId,
452
+ id: (_g = (_f = chunks.body) == null ? void 0 : _f.toolCall) == null ? void 0 : _g.id,
453
+ name: (_i = (_h = chunks.body) == null ? void 0 : _h.toolCall) == null ? void 0 : _i.name,
430
454
  willInterrupt
431
455
  },
432
456
  invokeStatus: "pending"
433
457
  });
434
458
  } else if (chunks.action === "afterToolCall") {
435
459
  const toolsMap = await this.getToolsMap();
436
- const willInterrupt = this.shouldInterruptToolCall(toolsMap.get((_l = (_k = chunks.body) == null ? void 0 : _k.toolCall) == null ? void 0 : _l.name));
437
- this.protocol.toolCallStatus({
460
+ const willInterrupt = this.shouldInterruptToolCall(toolsMap.get((_k = (_j = chunks.body) == null ? void 0 : _j.toolCall) == null ? void 0 : _k.name));
461
+ this.protocol.with(currentConversation).toolCallStatus({
438
462
  toolCall: {
439
- messageId: (_n = (_m = chunks.body) == null ? void 0 : _m.toolCall) == null ? void 0 : _n.messageId,
440
- id: (_p = (_o = chunks.body) == null ? void 0 : _o.toolCall) == null ? void 0 : _p.id,
441
- name: (_r = (_q = chunks.body) == null ? void 0 : _q.toolCall) == null ? void 0 : _r.name,
463
+ messageId: (_m = (_l = chunks.body) == null ? void 0 : _l.toolCall) == null ? void 0 : _m.messageId,
464
+ id: (_o = (_n = chunks.body) == null ? void 0 : _n.toolCall) == null ? void 0 : _o.id,
465
+ name: (_q = (_p = chunks.body) == null ? void 0 : _p.toolCall) == null ? void 0 : _q.name,
442
466
  willInterrupt
443
467
  },
444
468
  invokeStatus: "done",
445
- status: (_t = (_s = chunks.body) == null ? void 0 : _s.toolCallResult) == null ? void 0 : _t.status
469
+ status: (_s = (_r = chunks.body) == null ? void 0 : _r.toolCallResult) == null ? void 0 : _s.status,
470
+ invokeStartTime: (_u = (_t = chunks.body) == null ? void 0 : _t.toolCallResult) == null ? void 0 : _u.invokeStartTime,
471
+ invokeEndTime: (_w = (_v = chunks.body) == null ? void 0 : _v.toolCallResult) == null ? void 0 : _w.invokeEndTime,
472
+ content: (_y = (_x = chunks.body) == null ? void 0 : _x.toolCallResult) == null ? void 0 : _y.content
446
473
  });
447
474
  } else if (chunks.action === "beforeSendToolMessage") {
448
475
  const { messageId, messages } = chunks.body ?? {};
@@ -455,7 +482,7 @@ class AIEmployee {
455
482
  for (const { metadata } of messages) {
456
483
  const tools = toolsMap.get(metadata.toolName);
457
484
  const toolCallResult = toolCallResultMap.get(metadata.toolCallId);
458
- this.protocol.toolCallStatus({
485
+ this.protocol.with(currentConversation).toolCallStatus({
459
486
  toolCall: {
460
487
  messageId,
461
488
  id: metadata.toolCallId,
@@ -463,11 +490,16 @@ class AIEmployee {
463
490
  willInterrupt: this.shouldInterruptToolCall(tools)
464
491
  },
465
492
  invokeStatus: "confirmed",
466
- status: toolCallResult == null ? void 0 : toolCallResult.status
493
+ status: toolCallResult == null ? void 0 : toolCallResult.status,
494
+ invokeStartTime: toolCallResult == null ? void 0 : toolCallResult.invokeStartTime,
495
+ invokeEndTime: toolCallResult == null ? void 0 : toolCallResult.invokeEndTime,
496
+ content: toolCallResult == null ? void 0 : toolCallResult.content
467
497
  });
468
498
  }
469
499
  }
470
- this.protocol.newMessage();
500
+ this.protocol.with(currentConversation).newMessage();
501
+ } else if (chunks.action === "afterSubAgentInvoke") {
502
+ this.protocol.with(currentConversation).subAgentCompleted();
471
503
  }
472
504
  }
473
505
  }
@@ -475,7 +507,7 @@ class AIEmployee {
475
507
  this.sendErrorResponse("Empty message");
476
508
  return;
477
509
  }
478
- this.protocol.endStream();
510
+ this.protocol.with(aiEmployeeConversation).endStream();
479
511
  } catch (err) {
480
512
  this.ctx.log.error(err);
481
513
  if (err.name === "GraphRecursionError") {
@@ -484,7 +516,9 @@ class AIEmployee {
484
516
  this.sendErrorResponse(provider.parseResponseError(err));
485
517
  }
486
518
  } finally {
487
- this.ctx.res.end();
519
+ if (this.from === "main-agent") {
520
+ this.ctx.res.end();
521
+ }
488
522
  }
489
523
  }
490
524
  // === Prompts & knowledge base ===
@@ -566,6 +600,7 @@ ${workContextBackground.join("\n")}`;
566
600
  }
567
601
  }
568
602
  const availableSkills = await this.getAvailableSkills();
603
+ const availableAIEmployees = await this.getAvailableAIEmployees();
569
604
  const systemPrompt = (0, import_prompts.getSystemPrompt)({
570
605
  aiEmployee: {
571
606
  nickname: this.employee.nickname,
@@ -578,10 +613,13 @@ ${workContextBackground.join("\n")}`;
578
613
  dataSources: dataSourceMessage,
579
614
  environment: {
580
615
  database: this.db.sequelize.getDialect(),
581
- locale: this.ctx.getCurrentLocale() || "en-US"
616
+ locale: this.ctx.getCurrentLocale() || "en-US",
617
+ currentDateTime: getCurrentDateTimeForPrompt(this.ctx.getCurrentLocale(), getCurrentTimezone(this.ctx)),
618
+ timezone: getCurrentTimezone(this.ctx)
582
619
  },
583
620
  knowledgeBase,
584
- availableSkills
621
+ availableSkills,
622
+ availableAIEmployees
585
623
  });
586
624
  const { important } = this.ctx.action.params.values || {};
587
625
  if (important === "GraphRecursionError") {
@@ -706,23 +744,54 @@ If information is missing, clearly state it in the summary.</Important>`;
706
744
  transaction
707
745
  });
708
746
  }
709
- async updateToolCallInterrupted(messageId, toolCallId, interruptAction) {
710
- const [updated] = await this.aiToolMessagesModel.update(
711
- {
712
- invokeStatus: "interrupted",
713
- interruptActionOrder: interruptAction.order,
714
- interruptAction
715
- },
716
- {
747
+ async updateToolCallInterrupted(sessionId, messageId, toolCallId, interruptId, interruptAction) {
748
+ return await this.db.sequelize.transaction(async (transaction) => {
749
+ const [updated] = await this.aiToolMessagesModel.update(
750
+ {
751
+ invokeStatus: "interrupted",
752
+ interruptActionOrder: interruptAction.order,
753
+ interruptAction
754
+ },
755
+ {
756
+ where: {
757
+ sessionId,
758
+ messageId,
759
+ toolCallId,
760
+ invokeStatus: "init"
761
+ },
762
+ transaction
763
+ }
764
+ );
765
+ if (!updated) {
766
+ return updated;
767
+ }
768
+ const message = await this.aiMessagesModel.findOne({
717
769
  where: {
718
- sessionId: this.sessionId,
719
770
  messageId,
720
- toolCallId,
721
- invokeStatus: "init"
722
- }
771
+ sessionId
772
+ },
773
+ transaction
774
+ });
775
+ if (!message) {
776
+ return updated;
723
777
  }
724
- );
725
- return updated;
778
+ await this.aiMessagesModel.update(
779
+ {
780
+ metadata: {
781
+ ...message.get("metadata") ?? {},
782
+ interruptId
783
+ }
784
+ },
785
+ {
786
+ where: {
787
+ messageId,
788
+ sessionId
789
+ },
790
+ transaction
791
+ }
792
+ );
793
+ return updated;
794
+ });
726
795
  }
727
796
  async updateToolCallPending(messageId, toolCallId) {
728
797
  const [updated] = await this.aiToolMessagesModel.update(
@@ -784,7 +853,6 @@ If information is missing, clearly state it in the summary.</Important>`;
784
853
  var _a;
785
854
  return (_a = await this.aiToolMessagesModel.findOne({
786
855
  where: {
787
- sessionId: this.sessionId,
788
856
  messageId,
789
857
  toolCallId
790
858
  }
@@ -793,7 +861,6 @@ If information is missing, clearly state it in the summary.</Important>`;
793
861
  async getToolCallResultMap(messageId, toolCallIds) {
794
862
  const list = (await this.aiToolMessagesModel.findAll({
795
863
  where: {
796
- sessionId: this.sessionId,
797
864
  messageId,
798
865
  toolCallId: {
799
866
  [import_database.Op.in]: toolCallIds
@@ -802,19 +869,6 @@ If information is missing, clearly state it in the summary.</Important>`;
802
869
  })).map((it) => it.toJSON());
803
870
  return new Map(list.map((it) => [it.toolCallId, it]));
804
871
  }
805
- async getUserDecisions(messageId) {
806
- const allInterruptedToolCall = await this.aiToolMessagesModel.findAll({
807
- where: {
808
- messageId,
809
- interruptActionOrder: { [import_database.Op.not]: null }
810
- },
811
- order: [["interruptActionOrder", "ASC"]]
812
- });
813
- if (!allInterruptedToolCall.every((t) => t.invokeStatus === "waiting")) {
814
- return [];
815
- }
816
- return allInterruptedToolCall.map((item) => item.userDecision);
817
- }
818
872
  async cancelToolCall() {
819
873
  var _a;
820
874
  let messageId;
@@ -829,7 +883,6 @@ If information is missing, clearly state it in the summary.</Important>`;
829
883
  }
830
884
  const toolMessages = (await this.aiToolMessagesModel.findAll({
831
885
  where: {
832
- sessionId: this.sessionId,
833
886
  messageId,
834
887
  invokeStatus: {
835
888
  [import_database.Op.ne]: "confirmed"
@@ -839,7 +892,9 @@ If information is missing, clearly state it in the summary.</Important>`;
839
892
  if (!toolMessages || import_lodash.default.isEmpty(toolMessages)) {
840
893
  return;
841
894
  }
842
- const { model, service } = await this.getLLMService();
895
+ const { model, service } = await this.plugin.aiManager.getLLMService({
896
+ ...this.model
897
+ });
843
898
  const toolCallMap = await this.getToolCallMap(messageId);
844
899
  const now = /* @__PURE__ */ new Date();
845
900
  const toolMessageContent = "The user ignored the application for tools usage and will continued to ask questions";
@@ -1068,10 +1123,20 @@ If information is missing, clearly state it in the summary.</Important>`;
1068
1123
  const actionRequestsMap = new Map(actionRequests.map((x) => [x.name, x]));
1069
1124
  const reviewConfigsMap = new Map(reviewConfigs.map((x) => [x.actionName, x]));
1070
1125
  for (const [name, actionRequest] of actionRequestsMap.entries()) {
1126
+ const payload = actionRequest.description ? JSON.parse(actionRequest.description) : null;
1071
1127
  result.set(name, {
1072
1128
  order: order++,
1073
1129
  description: actionRequest.description,
1074
- allowedDecisions: (_a = reviewConfigsMap.get(name)) == null ? void 0 : _a.allowedDecisions
1130
+ allowedDecisions: (_a = reviewConfigsMap.get(name)) == null ? void 0 : _a.allowedDecisions,
1131
+ toolCall: {
1132
+ id: payload.toolCallId,
1133
+ name: payload.toolCallName
1134
+ },
1135
+ currentConversation: {
1136
+ sessionId: payload.sessionId,
1137
+ from: payload.from,
1138
+ username: payload.username
1139
+ }
1075
1140
  });
1076
1141
  }
1077
1142
  return result;
@@ -1079,6 +1144,10 @@ If information is missing, clearly state it in the summary.</Important>`;
1079
1144
  async getAIEmployeeTools() {
1080
1145
  var _a, _b;
1081
1146
  const tools = await this.listTools({ scope: "GENERAL" });
1147
+ if (this.webSearch === true) {
1148
+ const subAgentWebSearch = await this.toolsManager.getTools("subAgentWebSearch");
1149
+ tools.push(subAgentWebSearch);
1150
+ }
1082
1151
  const generalToolsNameSet = new Set(tools.map((x) => x.definition.name));
1083
1152
  const toolMap = await this.getToolsMap();
1084
1153
  const employeeTools = ((_a = this.employee.skillSettings) == null ? void 0 : _a.tools) ?? [];
@@ -1098,11 +1167,16 @@ If information is missing, clearly state it in the summary.</Important>`;
1098
1167
  async getAvailableSkills() {
1099
1168
  var _a, _b;
1100
1169
  const { skillsManager } = this.plugin.ai;
1170
+ const aIEmployeeTools = await this.getAIEmployeeTools();
1171
+ const getSkill = aIEmployeeTools.find((it) => it.definition.name === "getSkill");
1172
+ if (!getSkill) {
1173
+ return [];
1174
+ }
1101
1175
  const generalSkills = await skillsManager.listSkills({ scope: "GENERAL" });
1102
1176
  const specifiedSkillNames = ((_a = this.employee.skillSettings) == null ? void 0 : _a.skills) ?? [];
1103
1177
  const specifiedSkills = specifiedSkillNames.length ? await skillsManager.getSkills(specifiedSkillNames) : [];
1104
1178
  const skillFilter = ((_b = this.skillSettings) == null ? void 0 : _b.skills) ?? [];
1105
- return import_lodash.default.uniqBy([...generalSkills || [], ...specifiedSkills || []], "name").filter(
1179
+ return import_lodash.default.uniqBy([...specifiedSkills || [], ...generalSkills || []], "name").filter(
1106
1180
  (it) => skillFilter.length === 0 || skillFilter.includes(it.name)
1107
1181
  );
1108
1182
  }
@@ -1167,6 +1241,12 @@ If information is missing, clearly state it in the summary.</Important>`;
1167
1241
  }
1168
1242
  return result;
1169
1243
  }
1244
+ async getAvailableAIEmployees() {
1245
+ const availableAIEmployees = (await (0, import_shared.listAccessibleAIEmployees)(this.ctx)).map(
1246
+ (employee) => (0, import_shared.serializeEmployeeSummary)(this.ctx, employee)
1247
+ );
1248
+ return availableAIEmployees;
1249
+ }
1170
1250
  getMiddleware(options) {
1171
1251
  const { providerName, model, tools, baseToolNames, messageId, agentThread } = options;
1172
1252
  return [
@@ -1206,6 +1286,19 @@ If information is missing, clearly state it in the summary.</Important>`;
1206
1286
  listTools(filter) {
1207
1287
  return this.toolsManager.listTools(filter);
1208
1288
  }
1289
+ withRunMetadata(config) {
1290
+ return {
1291
+ ...config,
1292
+ metadata: {
1293
+ ...(config == null ? void 0 : config.metadata) ?? {},
1294
+ currentConversation: {
1295
+ sessionId: this.sessionId,
1296
+ from: this.from,
1297
+ username: this.employee.get("username")
1298
+ }
1299
+ }
1300
+ };
1301
+ }
1209
1302
  get toolsManager() {
1210
1303
  return this.ctx.app.aiManager.toolsManager;
1211
1304
  }
@@ -1228,6 +1321,33 @@ If information is missing, clearly state it in the summary.</Important>`;
1228
1321
  return this.ctx.db.getModel("aiFiles");
1229
1322
  }
1230
1323
  }
1324
+ function getCurrentTimezone(ctx) {
1325
+ var _a, _b, _c, _d, _e, _f, _g;
1326
+ const value = ((_a = ctx.get) == null ? void 0 : _a.call(ctx, "x-timezone")) || ((_c = (_b = ctx.request) == null ? void 0 : _b.get) == null ? void 0 : _c.call(_b, "x-timezone")) || ((_e = (_d = ctx.request) == null ? void 0 : _d.header) == null ? void 0 : _e["x-timezone"]) || ((_g = (_f = ctx.req) == null ? void 0 : _f.headers) == null ? void 0 : _g["x-timezone"]) || Intl.DateTimeFormat().resolvedOptions().timeZone;
1327
+ if (Array.isArray(value)) {
1328
+ return value[0];
1329
+ }
1330
+ return typeof value === "string" ? value : void 0;
1331
+ }
1332
+ function getCurrentDateTimeForPrompt(locale, timezone) {
1333
+ const now = /* @__PURE__ */ new Date();
1334
+ const normalizedLocale = locale || "en-US";
1335
+ try {
1336
+ const formatter = new Intl.DateTimeFormat(normalizedLocale, {
1337
+ timeZone: timezone,
1338
+ year: "numeric",
1339
+ month: "2-digit",
1340
+ day: "2-digit",
1341
+ hour: "2-digit",
1342
+ minute: "2-digit",
1343
+ second: "2-digit",
1344
+ hour12: false
1345
+ });
1346
+ return `${formatter.format(now)}${timezone ? ` (${timezone})` : ""}`;
1347
+ } catch (error) {
1348
+ return `${now.toISOString()}${timezone ? ` (${timezone})` : ""}`;
1349
+ }
1350
+ }
1231
1351
  class AgentThread {
1232
1352
  constructor(_sessionId, _thread) {
1233
1353
  this._sessionId = _sessionId;
@@ -1250,8 +1370,8 @@ class AgentThread {
1250
1370
  }
1251
1371
  }
1252
1372
  class ChatStreamProtocol {
1253
- constructor(ctx) {
1254
- this.ctx = ctx;
1373
+ constructor(streamConsumer) {
1374
+ this.streamConsumer = streamConsumer;
1255
1375
  }
1256
1376
  _statistics = {
1257
1377
  sent: 0,
@@ -1262,71 +1382,85 @@ class ChatStreamProtocol {
1262
1382
  this._statistics.sent = 0;
1263
1383
  }
1264
1384
  };
1265
- static create(ctx) {
1266
- return new ChatStreamProtocol(ctx);
1385
+ static fromContext(ctx) {
1386
+ return new ChatStreamProtocol(ctx.res);
1267
1387
  }
1268
- startStream() {
1269
- this._statistics.reset();
1270
- this.write({ type: "stream_start" });
1271
- }
1272
- endStream() {
1273
- this.write({ type: "stream_end" });
1274
- }
1275
- newMessage(content) {
1276
- this.write({ type: "new_message", body: content });
1277
- }
1278
- content(content) {
1279
- this.write({ type: "content", body: content });
1280
- }
1281
- webSearch(content) {
1282
- this.write({ type: "web_search", body: content });
1283
- }
1284
- reasoning(content) {
1285
- this.write({ type: "reasoning", body: content });
1286
- }
1287
- stopReasoning() {
1288
- this.write({
1289
- type: "reasoning",
1290
- body: {
1291
- status: "stop",
1292
- content: ""
1293
- }
1294
- });
1295
- }
1296
- toolCallChunks(content) {
1297
- this.write({ type: "tool_call_chunks", body: content });
1298
- }
1299
- toolCalls(content) {
1300
- this.write({ type: "tool_calls", body: content });
1301
- }
1302
- toolCallStatus({
1303
- toolCall,
1304
- invokeStatus,
1305
- status,
1306
- interruptAction
1307
- }) {
1308
- this.write({
1309
- type: "tool_call_status",
1310
- body: {
1388
+ with(conversation) {
1389
+ const write = ({ type, body }) => {
1390
+ const { sessionId, from, username } = conversation;
1391
+ const data = `data: ${JSON.stringify({ sessionId, from, username, type, body })}
1392
+
1393
+ `;
1394
+ this.streamConsumer.write(data);
1395
+ this._statistics.addSent(data.length);
1396
+ };
1397
+ return {
1398
+ startStream: () => {
1399
+ this._statistics.reset();
1400
+ write({ type: "stream_start" });
1401
+ },
1402
+ endStream: () => {
1403
+ write({ type: "stream_end" });
1404
+ },
1405
+ subAgentCompleted: () => {
1406
+ write({ type: "sub_agent_completed" });
1407
+ },
1408
+ newMessage: (content) => {
1409
+ write({ type: "new_message", body: content });
1410
+ },
1411
+ content: (content) => {
1412
+ write({ type: "content", body: content });
1413
+ },
1414
+ webSearch: (content) => {
1415
+ write({ type: "web_search", body: content });
1416
+ },
1417
+ reasoning: (content) => {
1418
+ write({ type: "reasoning", body: content });
1419
+ },
1420
+ stopReasoning: () => {
1421
+ write({
1422
+ type: "reasoning",
1423
+ body: {
1424
+ status: "stop",
1425
+ content: ""
1426
+ }
1427
+ });
1428
+ },
1429
+ toolCallChunks: (content) => {
1430
+ write({ type: "tool_call_chunks", body: content });
1431
+ },
1432
+ toolCalls: (content) => {
1433
+ write({ type: "tool_calls", body: content });
1434
+ },
1435
+ toolCallStatus: ({
1311
1436
  toolCall,
1312
1437
  invokeStatus,
1313
1438
  status,
1439
+ invokeStartTime,
1440
+ invokeEndTime,
1441
+ content,
1314
1442
  interruptAction
1443
+ }) => {
1444
+ write({
1445
+ type: "tool_call_status",
1446
+ body: {
1447
+ toolCall,
1448
+ invokeStatus,
1449
+ status,
1450
+ invokeStartTime,
1451
+ invokeEndTime,
1452
+ content,
1453
+ interruptAction
1454
+ }
1455
+ });
1315
1456
  }
1316
- });
1457
+ };
1317
1458
  }
1318
1459
  get statistics() {
1319
1460
  return {
1320
1461
  sent: this._statistics.sent
1321
1462
  };
1322
1463
  }
1323
- write({ type, body }) {
1324
- const data = `data: ${JSON.stringify({ type, body })}
1325
-
1326
- `;
1327
- this.ctx.res.write(data);
1328
- this._statistics.addSent(data.length);
1329
- }
1330
1464
  }
1331
1465
  class ResponseMetadataCollector extends import_base.BaseCallbackHandler {
1332
1466
  constructor(llmProvider, responseMetadata) {
@@ -1347,5 +1481,6 @@ class ResponseMetadataCollector extends import_base.BaseCallbackHandler {
1347
1481
  }
1348
1482
  // Annotate the CommonJS export names for ESM import in node:
1349
1483
  0 && (module.exports = {
1350
- AIEmployee
1484
+ AIEmployee,
1485
+ ChatStreamProtocol
1351
1486
  });