@nocobase/plugin-ai 2.4.0-alpha.3 → 2.4.0-alpha.4
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.
- package/dist/client/{244.276308c9b2090ec2.js → 244.12a92ac906b07849.js} +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client-v2/{244.e85b8d4659ca66c0.js → 244.a0c8684f23fa5fa9.js} +1 -1
- package/dist/client-v2/index.js +1 -1
- package/dist/common/ai-employee-validation.d.ts +2 -0
- package/dist/common/ai-employee-validation.js +6 -0
- package/dist/common/error-codes.d.ts +1 -0
- package/dist/common/error-codes.js +3 -0
- package/dist/externalVersion.js +15 -15
- package/dist/locale/en-US.json +2 -0
- package/dist/locale/zh-CN.json +2 -0
- package/dist/node_modules/@langchain/mistralai/package.json +1 -1
- package/dist/node_modules/@langchain/xai/package.json +1 -1
- package/dist/node_modules/fs-extra/package.json +1 -1
- package/dist/node_modules/jsonrepair/package.json +1 -1
- package/dist/node_modules/just-bash/package.json +1 -1
- package/dist/node_modules/nodejs-snowflake/package.json +1 -1
- package/dist/node_modules/openai/package.json +1 -1
- package/dist/node_modules/zod/package.json +1 -1
- package/dist/server/ai-employees/ai-employee.d.ts +28 -1
- package/dist/server/ai-employees/ai-employee.js +257 -34
- package/dist/server/ai-employees/ai-knowledge-base.js +11 -4
- package/dist/server/ai-employees/middleware/conversation.js +19 -20
- package/dist/server/ai-employees/middleware/index.d.ts +1 -0
- package/dist/server/ai-employees/middleware/index.js +2 -0
- package/dist/server/ai-employees/middleware/tool-result-integrity.d.ts +22 -0
- package/dist/server/ai-employees/middleware/tool-result-integrity.js +211 -0
- package/dist/server/resource/aiEmployees.js +26 -0
- package/package.json +2 -2
|
@@ -60,6 +60,7 @@ var import_attachments = require("../attachments");
|
|
|
60
60
|
var import_frontend_tools = require("../../common/frontend-tools");
|
|
61
61
|
var import_frontend_tools2 = require("../frontend-tools");
|
|
62
62
|
var import_reasoning_stream_state = require("./reasoning-stream-state");
|
|
63
|
+
const ABORTED_TOOL_CALL_CONTENT = "The tool call was interrupted because the conversation was aborted.";
|
|
63
64
|
class AIEmployee {
|
|
64
65
|
sessionId;
|
|
65
66
|
from = "main-agent";
|
|
@@ -78,6 +79,7 @@ class AIEmployee {
|
|
|
78
79
|
tools;
|
|
79
80
|
inWorkflow;
|
|
80
81
|
streamCached;
|
|
82
|
+
static conversationPersistenceQueues = /* @__PURE__ */ new WeakMap();
|
|
81
83
|
constructor({
|
|
82
84
|
ctx,
|
|
83
85
|
employee,
|
|
@@ -419,6 +421,7 @@ class AIEmployee {
|
|
|
419
421
|
async processChatStream(stream, options) {
|
|
420
422
|
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, _z;
|
|
421
423
|
const aiMessageIdMap = /* @__PURE__ */ new Map();
|
|
424
|
+
const persistedAIMessageIdMap = /* @__PURE__ */ new Map();
|
|
422
425
|
const { signal, providerName, llmService, model, provider, responseMetadata, allowEmpty = false } = options;
|
|
423
426
|
const reasoningState = new import_reasoning_stream_state.ReasoningStreamState();
|
|
424
427
|
const stopReasoning = async (conversation) => {
|
|
@@ -432,37 +435,38 @@ class AIEmployee {
|
|
|
432
435
|
}
|
|
433
436
|
};
|
|
434
437
|
let gathered;
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
})
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
438
|
+
let abortFinalization;
|
|
439
|
+
signal.addEventListener(
|
|
440
|
+
"abort",
|
|
441
|
+
() => {
|
|
442
|
+
abortFinalization = (async () => {
|
|
443
|
+
try {
|
|
444
|
+
await stopAllReasoning();
|
|
445
|
+
if ((gathered == null ? void 0 : gathered.type) === "ai") {
|
|
446
|
+
await this.finalizeAbortedAIMessage({
|
|
447
|
+
aiMessage: gathered,
|
|
448
|
+
providerName,
|
|
449
|
+
provider,
|
|
450
|
+
llmService,
|
|
451
|
+
model,
|
|
452
|
+
knownMessageId: persistedAIMessageIdMap.get(gathered.id)
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
} catch (e) {
|
|
456
|
+
this.logger.error("Fail to save message after conversation abort", gathered);
|
|
457
|
+
} finally {
|
|
458
|
+
await this.aiConversationsRepo.update({
|
|
459
|
+
values: { llmActiveState: "idle", read: true },
|
|
460
|
+
filter: {
|
|
461
|
+
sessionId: this.sessionId
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
await this.streamCached.clear();
|
|
461
465
|
}
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
+
})();
|
|
467
|
+
},
|
|
468
|
+
{ once: true }
|
|
469
|
+
);
|
|
466
470
|
try {
|
|
467
471
|
const aiEmployeeConversation = {
|
|
468
472
|
sessionId: this.sessionId,
|
|
@@ -525,6 +529,7 @@ class AIEmployee {
|
|
|
525
529
|
if (chunks.action === "AfterAIMessageSaved") {
|
|
526
530
|
await this.streamCached.skipped();
|
|
527
531
|
aiMessageIdMap.set(currentConversation.sessionId, chunks.body.messageId);
|
|
532
|
+
persistedAIMessageIdMap.set(chunks.body.id, chunks.body.messageId);
|
|
528
533
|
const data = responseMetadata.get(chunks.body.id);
|
|
529
534
|
if (data) {
|
|
530
535
|
const savedMessage = await this.aiMessagesModel.findOne({
|
|
@@ -629,6 +634,7 @@ class AIEmployee {
|
|
|
629
634
|
this.sendErrorResponse(provider.parseResponseError(err));
|
|
630
635
|
}
|
|
631
636
|
} finally {
|
|
637
|
+
await abortFinalization;
|
|
632
638
|
if (this.from === "main-agent") {
|
|
633
639
|
this.ctx.res.end();
|
|
634
640
|
}
|
|
@@ -804,6 +810,170 @@ If information is missing, clearly state it in the summary.</Important>`;
|
|
|
804
810
|
}
|
|
805
811
|
}
|
|
806
812
|
// === Tool calls ===
|
|
813
|
+
async withLockedConversation(callback) {
|
|
814
|
+
const persistenceQueues = AIEmployee.conversationPersistenceQueues.get(this.db) ?? /* @__PURE__ */ new Map();
|
|
815
|
+
AIEmployee.conversationPersistenceQueues.set(this.db, persistenceQueues);
|
|
816
|
+
const previous = persistenceQueues.get(this.sessionId) ?? Promise.resolve();
|
|
817
|
+
let release;
|
|
818
|
+
const current = new Promise((resolve) => {
|
|
819
|
+
release = resolve;
|
|
820
|
+
});
|
|
821
|
+
persistenceQueues.set(this.sessionId, current);
|
|
822
|
+
await previous;
|
|
823
|
+
try {
|
|
824
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
825
|
+
try {
|
|
826
|
+
return await this.aiChatConversation.withTransaction(async (conversation, transaction) => {
|
|
827
|
+
const lockedConversation = await this.aiConversationsModel.findOne({
|
|
828
|
+
where: { sessionId: this.sessionId },
|
|
829
|
+
transaction,
|
|
830
|
+
lock: transaction.LOCK.UPDATE
|
|
831
|
+
});
|
|
832
|
+
if (!lockedConversation) {
|
|
833
|
+
throw new Error(`AI conversation ${this.sessionId} not found`);
|
|
834
|
+
}
|
|
835
|
+
return await callback(conversation, transaction);
|
|
836
|
+
});
|
|
837
|
+
} catch (error) {
|
|
838
|
+
if (!(error instanceof import_database.UniqueConstraintError) || attempt === 1) {
|
|
839
|
+
throw error;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
throw new Error(`Failed to persist AI conversation ${this.sessionId}`);
|
|
844
|
+
} finally {
|
|
845
|
+
release();
|
|
846
|
+
if (persistenceQueues.get(this.sessionId) === current) {
|
|
847
|
+
persistenceQueues.delete(this.sessionId);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
async findPersistedAIMessage(transaction, langChainMessageId, knownMessageId) {
|
|
852
|
+
var _a;
|
|
853
|
+
if (knownMessageId) {
|
|
854
|
+
const knownMessage = await this.aiMessagesModel.findOne({
|
|
855
|
+
where: { sessionId: this.sessionId, messageId: knownMessageId },
|
|
856
|
+
transaction
|
|
857
|
+
});
|
|
858
|
+
if (((_a = knownMessage == null ? void 0 : knownMessage.get("metadata")) == null ? void 0 : _a.id) === langChainMessageId) {
|
|
859
|
+
return knownMessage;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
const messages = await this.aiMessagesModel.findAll({
|
|
863
|
+
where: { sessionId: this.sessionId, role: this.employee.username },
|
|
864
|
+
order: [["messageId", "DESC"]],
|
|
865
|
+
transaction
|
|
866
|
+
});
|
|
867
|
+
return messages.find((message) => {
|
|
868
|
+
var _a2;
|
|
869
|
+
return ((_a2 = message.get("metadata")) == null ? void 0 : _a2.id) === langChainMessageId;
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
async persistAIMessageInTransaction(conversation, transaction, options) {
|
|
873
|
+
const existingMessage = await this.findPersistedAIMessage(
|
|
874
|
+
transaction,
|
|
875
|
+
options.langChainMessageId,
|
|
876
|
+
options.knownMessageId
|
|
877
|
+
);
|
|
878
|
+
if (existingMessage) {
|
|
879
|
+
const message2 = existingMessage.toJSON();
|
|
880
|
+
const initializedToolCalls2 = await this.aiToolMessagesModel.findAll({
|
|
881
|
+
where: { sessionId: this.sessionId, messageId: message2.messageId },
|
|
882
|
+
transaction
|
|
883
|
+
});
|
|
884
|
+
return { message: message2, initializedToolCalls: initializedToolCalls2, created: false };
|
|
885
|
+
}
|
|
886
|
+
const message = await conversation.addMessages(options.values);
|
|
887
|
+
const initializedToolCalls = options.toolCalls.length ? await this.initToolCall(transaction, message.messageId, options.toolCalls) : [];
|
|
888
|
+
return { message, initializedToolCalls, created: true };
|
|
889
|
+
}
|
|
890
|
+
async persistAIMessage(options) {
|
|
891
|
+
return await this.withLockedConversation(async (conversation, transaction) => {
|
|
892
|
+
return await this.persistAIMessageInTransaction(conversation, transaction, options);
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
async finalizeAbortedAIMessage({
|
|
896
|
+
aiMessage,
|
|
897
|
+
providerName,
|
|
898
|
+
provider,
|
|
899
|
+
llmService,
|
|
900
|
+
model,
|
|
901
|
+
knownMessageId
|
|
902
|
+
}) {
|
|
903
|
+
const values = (0, import_utils2.convertAIMessage)({
|
|
904
|
+
aiEmployee: this,
|
|
905
|
+
providerName,
|
|
906
|
+
provider,
|
|
907
|
+
llmService,
|
|
908
|
+
model,
|
|
909
|
+
aiMessage
|
|
910
|
+
});
|
|
911
|
+
if (!values) {
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
values.metadata = { ...values.metadata, interrupted: true };
|
|
915
|
+
const toolCalls = aiMessage.tool_calls ?? [];
|
|
916
|
+
return await this.withLockedConversation(async (conversation, transaction) => {
|
|
917
|
+
var _a;
|
|
918
|
+
const result = await this.persistAIMessageInTransaction(conversation, transaction, {
|
|
919
|
+
values,
|
|
920
|
+
langChainMessageId: aiMessage.id,
|
|
921
|
+
toolCalls,
|
|
922
|
+
knownMessageId
|
|
923
|
+
});
|
|
924
|
+
const unfinishedToolCalls = result.initializedToolCalls.map((toolCall) => toolCall.toJSON()).filter((toolCall) => toolCall.invokeStatus !== "confirmed");
|
|
925
|
+
if (!result.created && (!result.initializedToolCalls.length || unfinishedToolCalls.length) && !((_a = result.message.metadata) == null ? void 0 : _a.interrupted)) {
|
|
926
|
+
const metadata = { ...result.message.metadata, interrupted: true };
|
|
927
|
+
await this.aiMessagesModel.update(
|
|
928
|
+
{ metadata },
|
|
929
|
+
{ where: { sessionId: this.sessionId, messageId: result.message.messageId }, transaction }
|
|
930
|
+
);
|
|
931
|
+
result.message.metadata = metadata;
|
|
932
|
+
}
|
|
933
|
+
if (!unfinishedToolCalls.length) {
|
|
934
|
+
return result;
|
|
935
|
+
}
|
|
936
|
+
const persistedToolCalls = result.message.toolCalls ?? toolCalls;
|
|
937
|
+
const toolCallMap = new Map(persistedToolCalls.map((toolCall) => [toolCall.id, toolCall]));
|
|
938
|
+
const now = /* @__PURE__ */ new Date();
|
|
939
|
+
await conversation.addMessages(
|
|
940
|
+
unfinishedToolCalls.map((toolCall) => ({
|
|
941
|
+
role: "tool",
|
|
942
|
+
content: { type: "text", content: ABORTED_TOOL_CALL_CONTENT },
|
|
943
|
+
metadata: {
|
|
944
|
+
id: `aborted-tool:${aiMessage.id}:${toolCall.toolCallId}`,
|
|
945
|
+
model,
|
|
946
|
+
provider: providerName,
|
|
947
|
+
llmService,
|
|
948
|
+
messageId: result.message.messageId,
|
|
949
|
+
toolCallId: toolCall.toolCallId,
|
|
950
|
+
toolName: toolCall.toolName,
|
|
951
|
+
toolCall: toolCallMap.get(toolCall.toolCallId),
|
|
952
|
+
autoCall: toolCall.auto
|
|
953
|
+
}
|
|
954
|
+
}))
|
|
955
|
+
);
|
|
956
|
+
for (const toolCall of unfinishedToolCalls) {
|
|
957
|
+
await this.aiToolMessagesModel.update(
|
|
958
|
+
{
|
|
959
|
+
invokeStatus: "confirmed",
|
|
960
|
+
status: "error",
|
|
961
|
+
content: ABORTED_TOOL_CALL_CONTENT,
|
|
962
|
+
invokeStartTime: toolCall.invokeStartTime ?? now,
|
|
963
|
+
invokeEndTime: now
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
where: {
|
|
967
|
+
id: toolCall.id,
|
|
968
|
+
invokeStatus: { [import_database.Op.ne]: "confirmed" }
|
|
969
|
+
},
|
|
970
|
+
transaction
|
|
971
|
+
}
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
return result;
|
|
975
|
+
});
|
|
976
|
+
}
|
|
807
977
|
async initToolCall(transaction, messageId, toolCalls) {
|
|
808
978
|
const nowTime = /* @__PURE__ */ new Date();
|
|
809
979
|
const toolMap = await this.getToolsMap();
|
|
@@ -956,6 +1126,39 @@ If information is missing, clearly state it in the summary.</Important>`;
|
|
|
956
1126
|
})).map((it) => it.toJSON());
|
|
957
1127
|
return new Map(list.map((it) => [it.toolCallId, it]));
|
|
958
1128
|
}
|
|
1129
|
+
async getToolCallResults(toolCallIds) {
|
|
1130
|
+
if (!toolCallIds.length) {
|
|
1131
|
+
return /* @__PURE__ */ new Map();
|
|
1132
|
+
}
|
|
1133
|
+
const list = (await this.aiToolMessagesModel.findAll({
|
|
1134
|
+
where: {
|
|
1135
|
+
sessionId: this.sessionId,
|
|
1136
|
+
toolCallId: {
|
|
1137
|
+
[import_database.Op.in]: toolCallIds
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
})).map((item) => item.toJSON());
|
|
1141
|
+
const invokeStatusPriority = { confirmed: 2, done: 1 };
|
|
1142
|
+
const results = /* @__PURE__ */ new Map();
|
|
1143
|
+
for (const item of list) {
|
|
1144
|
+
if (item.invokeStatus !== "confirmed" && item.invokeStatus !== "done") {
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
const existing = results.get(item.toolCallId);
|
|
1148
|
+
if (!existing) {
|
|
1149
|
+
results.set(item.toolCallId, item);
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
const priority = invokeStatusPriority[item.invokeStatus];
|
|
1153
|
+
const existingPriority = invokeStatusPriority[existing.invokeStatus];
|
|
1154
|
+
const updatedAt = item.updatedAt ? new Date(item.updatedAt).getTime() : 0;
|
|
1155
|
+
const existingUpdatedAt = existing.updatedAt ? new Date(existing.updatedAt).getTime() : 0;
|
|
1156
|
+
if (priority > existingPriority || priority === existingPriority && updatedAt > existingUpdatedAt) {
|
|
1157
|
+
results.set(item.toolCallId, item);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
return results;
|
|
1161
|
+
}
|
|
959
1162
|
async cancelToolCall() {
|
|
960
1163
|
var _a;
|
|
961
1164
|
let messageId;
|
|
@@ -1093,7 +1296,7 @@ If information is missing, clearly state it in the summary.</Important>`;
|
|
|
1093
1296
|
});
|
|
1094
1297
|
}
|
|
1095
1298
|
async formatMessages({ messages, provider }) {
|
|
1096
|
-
var _a, _b;
|
|
1299
|
+
var _a, _b, _c, _d;
|
|
1097
1300
|
const formattedMessages = [];
|
|
1098
1301
|
const workContextHandler = this.plugin.workContextHandler;
|
|
1099
1302
|
const normalizedMessages = await this.normalizeMessageAttachments(messages);
|
|
@@ -1160,13 +1363,15 @@ If information is missing, clearly state it in the summary.</Important>`;
|
|
|
1160
1363
|
}
|
|
1161
1364
|
if (msg.role === "tool") {
|
|
1162
1365
|
formattedMessages.push({
|
|
1366
|
+
id: (_a = msg.metadata) == null ? void 0 : _a.id,
|
|
1163
1367
|
role: "tool",
|
|
1164
1368
|
content,
|
|
1165
|
-
|
|
1369
|
+
name: (_b = msg.metadata) == null ? void 0 : _b.toolName,
|
|
1370
|
+
tool_call_id: (_c = msg.metadata) == null ? void 0 : _c.toolCallId
|
|
1166
1371
|
});
|
|
1167
1372
|
continue;
|
|
1168
1373
|
}
|
|
1169
|
-
const additionalKwargs = (0, import_tool_call_sanitizer.sanitizeAdditionalKwargsForToolCalls)((
|
|
1374
|
+
const additionalKwargs = (0, import_tool_call_sanitizer.sanitizeAdditionalKwargsForToolCalls)((_d = msg.metadata) == null ? void 0 : _d.additional_kwargs, msg.toolCalls, {
|
|
1170
1375
|
onDiscard: (info) => {
|
|
1171
1376
|
var _a2;
|
|
1172
1377
|
this.logger.warn("Discard malformed raw tool calls from AI message", {
|
|
@@ -1415,7 +1620,22 @@ If information is missing, clearly state it in the summary.</Important>`;
|
|
|
1415
1620
|
(0, import_middleware.toolCallStatusMiddleware)(this),
|
|
1416
1621
|
...inWorkflow ? [(0, import_middleware.workflowHistoryMiddleware)(this, this.db)] : [],
|
|
1417
1622
|
(0, import_middleware.conversationMiddleware)(this, { providerName, provider, llmService, model, messageId, agentThread }),
|
|
1418
|
-
(0, import_middleware.toolCallSanitizerMiddleware)({ logger: this.logger })
|
|
1623
|
+
(0, import_middleware.toolCallSanitizerMiddleware)({ logger: this.logger }),
|
|
1624
|
+
(0, import_middleware.toolResultIntegrityMiddleware)({
|
|
1625
|
+
sessionId: this.sessionId,
|
|
1626
|
+
logger: this.logger,
|
|
1627
|
+
loadToolResults: async (toolCallIds) => {
|
|
1628
|
+
try {
|
|
1629
|
+
return await this.getToolCallResults(toolCallIds);
|
|
1630
|
+
} catch (error) {
|
|
1631
|
+
this.logger.warn("Failed to load persisted tool results before model call", {
|
|
1632
|
+
sessionId: this.sessionId,
|
|
1633
|
+
error
|
|
1634
|
+
});
|
|
1635
|
+
return /* @__PURE__ */ new Map();
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
})
|
|
1419
1639
|
];
|
|
1420
1640
|
}
|
|
1421
1641
|
async getCurrentThread() {
|
|
@@ -1473,6 +1693,9 @@ If information is missing, clearly state it in the summary.</Important>`;
|
|
|
1473
1693
|
get aiMessagesRepo() {
|
|
1474
1694
|
return this.ctx.db.getRepository("aiMessages");
|
|
1475
1695
|
}
|
|
1696
|
+
get aiConversationsModel() {
|
|
1697
|
+
return this.ctx.db.getModel("aiConversations");
|
|
1698
|
+
}
|
|
1476
1699
|
get aiMessagesModel() {
|
|
1477
1700
|
return this.ctx.db.getModel("aiMessages");
|
|
1478
1701
|
}
|
|
@@ -51,6 +51,7 @@ module.exports = __toCommonJS(ai_knowledge_base_exports);
|
|
|
51
51
|
var import_prompts = require("@langchain/core/prompts");
|
|
52
52
|
var import_ai_feature_manager = require("../manager/ai-feature-manager");
|
|
53
53
|
var import_lodash = __toESM(require("lodash"));
|
|
54
|
+
var import_ai_employee_validation = require("../../common/ai-employee-validation");
|
|
54
55
|
const KNOWLEDGE_BASE_RETRIEVAL_STRATEGIES = ["always", "onDemand"];
|
|
55
56
|
const isRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
56
57
|
const getRoleNames = (roles) => Array.isArray(roles) ? Array.from(
|
|
@@ -120,15 +121,21 @@ class KnowledgeBaseManager {
|
|
|
120
121
|
return "Specified knowledge base not existed";
|
|
121
122
|
}
|
|
122
123
|
const { knowledgeBaseKeys = [], topK, score } = employee.knowledgeBase ?? {};
|
|
123
|
-
const
|
|
124
|
+
const knowledgeBasePrompt = employee.knowledgeBasePrompt ?? "{knowledgeBaseData}";
|
|
124
125
|
const docs = await this.plugin.features.knowledgeBase.search({ knowledgeBaseKeys, query, topK, score, roleNames });
|
|
125
126
|
if (!(docs == null ? void 0 : docs.length)) {
|
|
126
127
|
return "No document match in knowledge base";
|
|
127
128
|
}
|
|
128
129
|
const knowledgeBaseData = docs.map((doc) => buildKnowledgeBaseContent(doc.content, doc.metadata)).join("\n");
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
130
|
+
if (import_lodash.default.isEmpty(knowledgeBaseData)) {
|
|
131
|
+
return "No document match in knowledge base";
|
|
132
|
+
}
|
|
133
|
+
if (!(0, import_ai_employee_validation.hasKnowledgeBaseDataPlaceholder)(knowledgeBasePrompt)) {
|
|
134
|
+
return `${knowledgeBasePrompt}
|
|
135
|
+
|
|
136
|
+
${knowledgeBaseData}`;
|
|
137
|
+
}
|
|
138
|
+
return import_prompts.ChatPromptTemplate.fromTemplate(knowledgeBasePrompt).format({ knowledgeBaseData });
|
|
132
139
|
}
|
|
133
140
|
async hasAccessibleKnowledgeBase({ employee, roleNames }) {
|
|
134
141
|
var _a;
|
|
@@ -179,31 +179,30 @@ const conversationMiddleware = (aiEmployee, options) => {
|
|
|
179
179
|
const toolCalls = aiMessage.tool_calls;
|
|
180
180
|
const values = convertAIMessage(aiMessage);
|
|
181
181
|
if (values) {
|
|
182
|
-
await aiEmployee.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const toolsMap = await aiEmployee.getToolsMap();
|
|
187
|
-
const initializedToolCalls = await aiEmployee.initToolCall(
|
|
188
|
-
transaction,
|
|
189
|
-
result.messageId,
|
|
190
|
-
toolCalls
|
|
191
|
-
);
|
|
192
|
-
fillToolCall(result, toolsMap, initializedToolCalls, toolCalls);
|
|
193
|
-
}
|
|
182
|
+
const result = await aiEmployee.persistAIMessage({
|
|
183
|
+
values,
|
|
184
|
+
langChainMessageId: aiMessage.id,
|
|
185
|
+
toolCalls: toolCalls ?? []
|
|
194
186
|
});
|
|
187
|
+
newState.messageId = result.message.messageId;
|
|
195
188
|
if (toolCalls == null ? void 0 : toolCalls.length) {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
189
|
+
const toolsMap = await aiEmployee.getToolsMap();
|
|
190
|
+
fillToolCall(result.message, toolsMap, result.initializedToolCalls, toolCalls);
|
|
191
|
+
}
|
|
192
|
+
if (result.created) {
|
|
193
|
+
if (toolCalls == null ? void 0 : toolCalls.length) {
|
|
194
|
+
(_b = runtime.writer) == null ? void 0 : _b.call(runtime, {
|
|
195
|
+
action: "initToolCalls",
|
|
196
|
+
body: { toolCalls },
|
|
197
|
+
currentConversation
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
(_c = runtime.writer) == null ? void 0 : _c.call(runtime, {
|
|
201
|
+
action: "AfterAIMessageSaved",
|
|
202
|
+
body: { id: aiMessage.id, messageId: newState.messageId },
|
|
199
203
|
currentConversation
|
|
200
204
|
});
|
|
201
205
|
}
|
|
202
|
-
(_c = runtime.writer) == null ? void 0 : _c.call(runtime, {
|
|
203
|
-
action: "AfterAIMessageSaved",
|
|
204
|
-
body: { id: aiMessage.id, messageId: newState.messageId },
|
|
205
|
-
currentConversation
|
|
206
|
-
});
|
|
207
206
|
}
|
|
208
207
|
return newState;
|
|
209
208
|
} catch (e) {
|
|
@@ -26,6 +26,7 @@ module.exports = __toCommonJS(middleware_exports);
|
|
|
26
26
|
__reExport(middleware_exports, require("./conversation"), module.exports);
|
|
27
27
|
__reExport(middleware_exports, require("./skill-tools"), module.exports);
|
|
28
28
|
__reExport(middleware_exports, require("./tool-call-sanitizer"), module.exports);
|
|
29
|
+
__reExport(middleware_exports, require("./tool-result-integrity"), module.exports);
|
|
29
30
|
__reExport(middleware_exports, require("./tools"), module.exports);
|
|
30
31
|
__reExport(middleware_exports, require("./workflow-history"), module.exports);
|
|
31
32
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -33,6 +34,7 @@ __reExport(middleware_exports, require("./workflow-history"), module.exports);
|
|
|
33
34
|
...require("./conversation"),
|
|
34
35
|
...require("./skill-tools"),
|
|
35
36
|
...require("./tool-call-sanitizer"),
|
|
37
|
+
...require("./tool-result-integrity"),
|
|
36
38
|
...require("./tools"),
|
|
37
39
|
...require("./workflow-history")
|
|
38
40
|
});
|
|
@@ -0,0 +1,22 @@
|
|
|
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 { BaseMessage } from '@langchain/core/messages';
|
|
10
|
+
import type { AIToolMessage } from '../../types/ai-message.type';
|
|
11
|
+
type ToolResultIntegrityLogger = {
|
|
12
|
+
warn: (message: string, meta?: Record<string, unknown>) => void;
|
|
13
|
+
};
|
|
14
|
+
export type NormalizeToolCallHistoryOptions = {
|
|
15
|
+
sessionId: string;
|
|
16
|
+
logger?: ToolResultIntegrityLogger;
|
|
17
|
+
loadToolResults: (toolCallIds: string[]) => Promise<Map<string, AIToolMessage>>;
|
|
18
|
+
};
|
|
19
|
+
export declare const isToolCallHistoryValid: (messages: readonly BaseMessage[]) => boolean;
|
|
20
|
+
export declare const normalizeToolCallHistory: (messages: readonly BaseMessage[], options: NormalizeToolCallHistoryOptions) => Promise<BaseMessage[]>;
|
|
21
|
+
export declare const toolResultIntegrityMiddleware: (options: NormalizeToolCallHistoryOptions) => import("langchain/dist/agents/middleware/types.cjs").AgentMiddleware<undefined, undefined, unknown, readonly (import("@langchain/core/dist/tools").ClientTool | import("@langchain/core/dist/tools").ServerTool)[]>;
|
|
22
|
+
export {};
|