@nocobase/plugin-ai 2.2.0-beta.7 → 2.2.0-beta.9
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/ai/docs/nocobase/api/app/env.md +28 -1
- package/dist/ai/docs/nocobase/api/cli/config/delete.md +9 -6
- package/dist/ai/docs/nocobase/api/cli/config/get.md +8 -6
- package/dist/ai/docs/nocobase/api/cli/config/index.md +40 -26
- package/dist/ai/docs/nocobase/api/cli/config/set.md +15 -8
- package/dist/ai/docs/nocobase/api/cli/env/auth.md +53 -5
- package/dist/ai/docs/nocobase/api/cli/self/check.md +19 -2
- package/dist/ai/docs/nocobase/api/cli/self/index.md +1 -1
- package/dist/ai/docs/nocobase/api/cli/self/update.md +17 -3
- package/dist/ai/docs/nocobase/file-manager/field-attachment.md +6 -0
- package/dist/ai/docs/nocobase/file-manager/file-preview/index.md +3 -12
- package/dist/ai/docs/nocobase/file-manager/storage/aliyun-oss.md +9 -0
- package/dist/ai/docs/nocobase/file-manager/storage/amazon-s3.md +9 -0
- package/dist/ai/docs/nocobase/file-manager/storage/index.md +23 -0
- package/dist/ai/docs/nocobase/file-manager/storage/local.md +9 -0
- package/dist/ai/docs/nocobase/file-manager/storage/migrate-to-s3-pro.md +269 -0
- package/dist/ai/docs/nocobase/file-manager/storage/tencent-cos.md +9 -0
- package/dist/ai/docs/nocobase/get-started/installation/docker-caddy.mdx +175 -0
- package/dist/ai/docs/nocobase/get-started/installation/docker-nginx.mdx +176 -0
- package/dist/ai/docs/nocobase/get-started/installation/docker.mdx +94 -1
- package/dist/ai/docs/nocobase/get-started/installation/env.md +14 -4
- package/dist/ai/docs/nocobase/nocobase-cli/installation/cli.md +2 -0
- package/dist/ai/docs/nocobase/ops-management/version-control/index.md +1 -0
- package/dist/client/559.9f97ebcdb0bd6231.js +10 -0
- package/dist/client/{604.de96f3ec4d471afd.js → 604.89c674f35b52b4ef.js} +1 -1
- package/dist/client/index.js +3 -3
- package/dist/client/llm-providers/mistral/ModelSettings.d.ts +10 -0
- package/dist/client/llm-providers/mistral/index.d.ts +10 -0
- package/dist/client/llm-services/utils.d.ts +5 -0
- package/dist/externalVersion.js +16 -16
- package/dist/locale/en-US.json +1 -0
- package/dist/locale/zh-CN.json +1 -0
- package/dist/node_modules/@langchain/mistralai/LICENSE +21 -0
- package/dist/node_modules/@langchain/mistralai/dist/_virtual/rolldown_runtime.cjs +25 -0
- package/dist/node_modules/@langchain/mistralai/dist/chat_models.cjs +859 -0
- package/dist/node_modules/@langchain/mistralai/dist/chat_models.d.cts +541 -0
- package/dist/node_modules/@langchain/mistralai/dist/chat_models.d.ts +541 -0
- package/dist/node_modules/@langchain/mistralai/dist/chat_models.js +857 -0
- package/dist/node_modules/@langchain/mistralai/dist/embeddings.cjs +140 -0
- package/dist/node_modules/@langchain/mistralai/dist/embeddings.d.cts +116 -0
- package/dist/node_modules/@langchain/mistralai/dist/embeddings.d.ts +116 -0
- package/dist/node_modules/@langchain/mistralai/dist/embeddings.js +139 -0
- package/dist/node_modules/@langchain/mistralai/dist/index.cjs +21 -0
- package/dist/node_modules/@langchain/mistralai/dist/index.d.cts +4 -0
- package/dist/node_modules/@langchain/mistralai/dist/index.d.ts +4 -0
- package/dist/node_modules/@langchain/mistralai/dist/index.js +5 -0
- package/dist/node_modules/@langchain/mistralai/dist/llms.cjs +275 -0
- package/dist/node_modules/@langchain/mistralai/dist/llms.d.cts +147 -0
- package/dist/node_modules/@langchain/mistralai/dist/llms.d.ts +147 -0
- package/dist/node_modules/@langchain/mistralai/dist/llms.js +274 -0
- package/dist/node_modules/@langchain/mistralai/dist/utils.cjs +61 -0
- package/dist/node_modules/@langchain/mistralai/dist/utils.js +59 -0
- package/dist/node_modules/@langchain/mistralai/package.json +1 -0
- package/dist/node_modules/@langchain/xai/dist/index.cjs +2 -2
- 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.js +19 -6
- package/dist/server/ai-employees/checkpoints/cleaner.d.ts +2 -0
- package/dist/server/ai-employees/checkpoints/cleaner.js +11 -1
- package/dist/server/ai-employees/middleware/conversation.d.ts +2 -0
- package/dist/server/ai-employees/middleware/conversation.js +2 -1
- 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-call-sanitizer.d.ts +16 -0
- package/dist/server/ai-employees/middleware/tool-call-sanitizer.js +90 -0
- package/dist/server/ai-employees/tool-call-sanitizer.d.ts +26 -0
- package/dist/server/ai-employees/tool-call-sanitizer.js +84 -0
- package/dist/server/ai-employees/utils.d.ts +3 -1
- package/dist/server/ai-employees/utils.js +16 -2
- package/dist/server/llm-providers/mistral.d.ts +62 -0
- package/dist/server/llm-providers/mistral.js +265 -0
- package/dist/server/llm-providers/provider.d.ts +6 -2
- package/dist/server/llm-providers/provider.js +27 -14
- package/dist/server/plugin.js +2 -0
- package/dist/server/workflow/nodes/employee/index.js +92 -46
- package/dist/server/workflow/nodes/employee/tools.js +8 -1
- package/package.json +3 -2
- package/dist/client/559.a0f2f1cc2be3c039.js +0 -10
|
@@ -0,0 +1,62 @@
|
|
|
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 { EmbeddingsInterface } from '@langchain/core/embeddings';
|
|
10
|
+
import { AIMessage, AIMessageChunk } from '@langchain/core/messages';
|
|
11
|
+
import { ChatMistralAI } from '@langchain/mistralai';
|
|
12
|
+
import { AttachmentModel } from '@nocobase/plugin-file-manager';
|
|
13
|
+
import { EmbeddingProvider, LLMProvider, LLMProviderInvokeOptions } from './provider';
|
|
14
|
+
import { LLMProviderMeta } from '../manager/ai-manager';
|
|
15
|
+
import { AIChatContext, AIMessageInput } from '../types/ai-chat-conversation.type';
|
|
16
|
+
import { Model } from '@nocobase/database';
|
|
17
|
+
type MistralCallOptions = LLMProviderInvokeOptions & {
|
|
18
|
+
response_format?: {
|
|
19
|
+
type: 'text' | 'json_object';
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
type MistralBeforeRequestHook = (request: Request) => Request | void | Promise<Request | void>;
|
|
23
|
+
export declare const injectMistralReasoningEffort: MistralBeforeRequestHook;
|
|
24
|
+
export declare class MistralProvider extends LLMProvider {
|
|
25
|
+
chatModel: ChatMistralAI;
|
|
26
|
+
get baseURL(): string;
|
|
27
|
+
createModel(): ChatMistralAI<import("@langchain/mistralai/dist/chat_models").ChatMistralAICallOptions>;
|
|
28
|
+
stream(context: AIChatContext, options?: MistralCallOptions): Promise<any>;
|
|
29
|
+
invoke(context: AIChatContext, options?: MistralCallOptions): Promise<any>;
|
|
30
|
+
listModels(): Promise<{
|
|
31
|
+
models?: {
|
|
32
|
+
id: string;
|
|
33
|
+
}[];
|
|
34
|
+
code?: number;
|
|
35
|
+
errMsg?: string;
|
|
36
|
+
}>;
|
|
37
|
+
protected isApiSupportedAttachment(attachment: AttachmentModel): boolean;
|
|
38
|
+
reshapeAIMessage({ aiMessage, values }: {
|
|
39
|
+
aiMessage: AIMessage;
|
|
40
|
+
values: AIMessageInput;
|
|
41
|
+
}): void;
|
|
42
|
+
parseResponseMessage(message: Model): {
|
|
43
|
+
key: any;
|
|
44
|
+
createdAt: any;
|
|
45
|
+
content: any;
|
|
46
|
+
role: any;
|
|
47
|
+
};
|
|
48
|
+
parseResponseChunk(chunk: unknown): string;
|
|
49
|
+
parseReasoningContent(chunk: AIMessageChunk): {
|
|
50
|
+
status: string;
|
|
51
|
+
content: string;
|
|
52
|
+
} | null;
|
|
53
|
+
private withResponseFormat;
|
|
54
|
+
private getResolvedServerURL;
|
|
55
|
+
private buildMistralRequestURL;
|
|
56
|
+
}
|
|
57
|
+
export declare class MistralEmbeddingProvider extends EmbeddingProvider {
|
|
58
|
+
protected getDefaultUrl(): string;
|
|
59
|
+
createEmbedding(): EmbeddingsInterface;
|
|
60
|
+
}
|
|
61
|
+
export declare const mistralProviderOptions: LLMProviderMeta;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,265 @@
|
|
|
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 mistral_exports = {};
|
|
28
|
+
__export(mistral_exports, {
|
|
29
|
+
MistralEmbeddingProvider: () => MistralEmbeddingProvider,
|
|
30
|
+
MistralProvider: () => MistralProvider,
|
|
31
|
+
injectMistralReasoningEffort: () => injectMistralReasoningEffort,
|
|
32
|
+
mistralProviderOptions: () => mistralProviderOptions
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(mistral_exports);
|
|
35
|
+
var import_mistralai = require("@langchain/mistralai");
|
|
36
|
+
var import_utils = require("@nocobase/utils");
|
|
37
|
+
var import_provider = require("./provider");
|
|
38
|
+
var import_ai_manager = require("../manager/ai-manager");
|
|
39
|
+
const MISTRAL_URL = "https://api.mistral.ai";
|
|
40
|
+
const MISTRAL_REASONING_EFFORT = "high";
|
|
41
|
+
const MISTRAL_REASONING_MODELS = /* @__PURE__ */ new Set(["mistral-small-latest", "mistral-medium-3-5"]);
|
|
42
|
+
function omitDisabledNumberOptions(options) {
|
|
43
|
+
for (const key of ["maxTokens", "maxRetries"]) {
|
|
44
|
+
if (options[key] === -1) {
|
|
45
|
+
delete options[key];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function extractTextChunks(content) {
|
|
50
|
+
if (typeof content === "string") {
|
|
51
|
+
return content;
|
|
52
|
+
}
|
|
53
|
+
if (!Array.isArray(content)) {
|
|
54
|
+
return "";
|
|
55
|
+
}
|
|
56
|
+
return content.filter((chunk) => chunk && typeof chunk === "object").filter((chunk) => chunk.type === "text" && typeof chunk.text === "string").map((chunk) => chunk.text).join("");
|
|
57
|
+
}
|
|
58
|
+
function extractThinkingChunks(content) {
|
|
59
|
+
if (!Array.isArray(content)) {
|
|
60
|
+
return "";
|
|
61
|
+
}
|
|
62
|
+
return content.filter((chunk) => chunk && typeof chunk === "object").filter((chunk) => chunk.type === "thinking" && Array.isArray(chunk.thinking)).map((chunk) => extractTextChunks(chunk.thinking)).join("");
|
|
63
|
+
}
|
|
64
|
+
const injectMistralReasoningEffort = async (request) => {
|
|
65
|
+
if (request.method !== "POST") {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const contentType = request.headers.get("content-type") || "";
|
|
69
|
+
if (!contentType.toLowerCase().includes("application/json")) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const body = await request.clone().json().catch(() => null);
|
|
73
|
+
if (!body || typeof body !== "object") {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (typeof body.model !== "string" || !MISTRAL_REASONING_MODELS.has(body.model)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const headers = new Headers(request.headers);
|
|
80
|
+
headers.delete("content-length");
|
|
81
|
+
return new Request(request, {
|
|
82
|
+
headers,
|
|
83
|
+
body: JSON.stringify({
|
|
84
|
+
...body,
|
|
85
|
+
reasoning_effort: MISTRAL_REASONING_EFFORT
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
class MistralProvider extends import_provider.LLMProvider {
|
|
90
|
+
get baseURL() {
|
|
91
|
+
return MISTRAL_URL;
|
|
92
|
+
}
|
|
93
|
+
createModel() {
|
|
94
|
+
const { apiKey } = this.serviceOptions || {};
|
|
95
|
+
const { responseFormat, structuredOutput, ...modelOptions } = this.modelOptions || {};
|
|
96
|
+
omitDisabledNumberOptions(modelOptions);
|
|
97
|
+
const beforeRequestHooks = Array.isArray(modelOptions.beforeRequestHooks) ? [injectMistralReasoningEffort, ...modelOptions.beforeRequestHooks] : [injectMistralReasoningEffort];
|
|
98
|
+
return new import_mistralai.ChatMistralAI({
|
|
99
|
+
apiKey,
|
|
100
|
+
...modelOptions,
|
|
101
|
+
beforeRequestHooks,
|
|
102
|
+
serverURL: this.getResolvedServerURL(),
|
|
103
|
+
verbose: false
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async stream(context, options) {
|
|
107
|
+
return super.stream(context, this.withResponseFormat(options));
|
|
108
|
+
}
|
|
109
|
+
async invoke(context, options) {
|
|
110
|
+
return super.invoke(context, this.withResponseFormat(options));
|
|
111
|
+
}
|
|
112
|
+
async listModels() {
|
|
113
|
+
var _a, _b, _c, _d;
|
|
114
|
+
const options = this.serviceOptions || {};
|
|
115
|
+
const apiKey = options.apiKey;
|
|
116
|
+
let url;
|
|
117
|
+
try {
|
|
118
|
+
url = this.buildMistralRequestURL("v1/models");
|
|
119
|
+
} catch (e) {
|
|
120
|
+
return { code: 400, errMsg: e instanceof Error ? e.message : String(e) };
|
|
121
|
+
}
|
|
122
|
+
if (!apiKey) {
|
|
123
|
+
return { code: 400, errMsg: "API Key required" };
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const res = await (0, import_utils.serverRequest)({
|
|
127
|
+
method: "GET",
|
|
128
|
+
url,
|
|
129
|
+
headers: {
|
|
130
|
+
Authorization: `Bearer ${apiKey}`
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
return { models: (_a = res == null ? void 0 : res.data) == null ? void 0 : _a.data };
|
|
134
|
+
} catch (e) {
|
|
135
|
+
const error = e;
|
|
136
|
+
const status = ((_b = error.response) == null ? void 0 : _b.status) || 500;
|
|
137
|
+
const data = (_c = error.response) == null ? void 0 : _c.data;
|
|
138
|
+
const errorMsg = (typeof data === "object" ? data.message : void 0) || (typeof data === "object" && typeof data.detail === "object" ? data.detail.message : void 0) || (typeof data === "object" && typeof data.detail === "string" ? data.detail : void 0) || (typeof data === "string" ? data : void 0) || ((_d = error.response) == null ? void 0 : _d.statusText) || error.message;
|
|
139
|
+
return { code: status, errMsg: errorMsg };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
isApiSupportedAttachment(attachment) {
|
|
143
|
+
var _a;
|
|
144
|
+
return ((_a = attachment.mimetype) == null ? void 0 : _a.startsWith("image/")) ?? false;
|
|
145
|
+
}
|
|
146
|
+
reshapeAIMessage({ aiMessage, values }) {
|
|
147
|
+
const reasoning = extractThinkingChunks(aiMessage.content);
|
|
148
|
+
if (Array.isArray(aiMessage.content)) {
|
|
149
|
+
aiMessage.content = extractTextChunks(aiMessage.content);
|
|
150
|
+
}
|
|
151
|
+
if (!reasoning) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
values.metadata.additional_kwargs = {
|
|
155
|
+
...values.metadata.additional_kwargs ?? {},
|
|
156
|
+
reasoning_content: reasoning
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
parseResponseMessage(message) {
|
|
160
|
+
var _a, _b, _c, _d;
|
|
161
|
+
const result = super.parseResponseMessage(message);
|
|
162
|
+
if (["user", "tool"].includes(result == null ? void 0 : result.role)) {
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
const metadataReasoning = (_c = (_b = (_a = result == null ? void 0 : result.content) == null ? void 0 : _a.metadata) == null ? void 0 : _b.additional_kwargs) == null ? void 0 : _c.reasoning_content;
|
|
166
|
+
if (typeof metadataReasoning === "string" && metadataReasoning) {
|
|
167
|
+
result.content = {
|
|
168
|
+
...result.content ?? {},
|
|
169
|
+
reasoning: {
|
|
170
|
+
status: "stop",
|
|
171
|
+
content: metadataReasoning
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
const rawContent = (_d = result == null ? void 0 : result.content) == null ? void 0 : _d.content;
|
|
177
|
+
const reasoning = extractThinkingChunks(rawContent);
|
|
178
|
+
if (reasoning) {
|
|
179
|
+
result.content = {
|
|
180
|
+
...result.content ?? {},
|
|
181
|
+
content: extractTextChunks(rawContent),
|
|
182
|
+
reasoning: {
|
|
183
|
+
status: "stop",
|
|
184
|
+
content: reasoning
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
parseResponseChunk(chunk) {
|
|
191
|
+
if (Array.isArray(chunk)) {
|
|
192
|
+
return extractTextChunks(chunk);
|
|
193
|
+
}
|
|
194
|
+
return super.parseResponseChunk(chunk);
|
|
195
|
+
}
|
|
196
|
+
parseReasoningContent(chunk) {
|
|
197
|
+
const content = extractThinkingChunks(chunk == null ? void 0 : chunk.content);
|
|
198
|
+
if (!content) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
status: "streaming",
|
|
203
|
+
content
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
withResponseFormat(options) {
|
|
207
|
+
var _a;
|
|
208
|
+
const responseFormat = (_a = this.modelOptions) == null ? void 0 : _a.responseFormat;
|
|
209
|
+
if (responseFormat !== "json_object") {
|
|
210
|
+
return options;
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
...options || {},
|
|
214
|
+
response_format: {
|
|
215
|
+
type: responseFormat
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
getResolvedServerURL() {
|
|
220
|
+
return this.getResolvedBaseURL().replace(/\/v1$/, "");
|
|
221
|
+
}
|
|
222
|
+
buildMistralRequestURL(pathname) {
|
|
223
|
+
const url = new URL(pathname.replace(/^\/+/, ""), `${this.getResolvedServerURL()}/`).toString();
|
|
224
|
+
(0, import_utils.checkUrlAgainstWhitelist)(url);
|
|
225
|
+
return url;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
class MistralEmbeddingProvider extends import_provider.EmbeddingProvider {
|
|
229
|
+
getDefaultUrl() {
|
|
230
|
+
return MISTRAL_URL;
|
|
231
|
+
}
|
|
232
|
+
createEmbedding() {
|
|
233
|
+
return new import_mistralai.MistralAIEmbeddings({
|
|
234
|
+
apiKey: this.apiKey,
|
|
235
|
+
serverURL: this.baseURL.replace(/\/v1$/, ""),
|
|
236
|
+
model: this.model
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const mistralProviderOptions = {
|
|
241
|
+
title: "Mistral AI",
|
|
242
|
+
supportedModel: [import_ai_manager.SupportedModel.LLM, import_ai_manager.SupportedModel.EMBEDDING],
|
|
243
|
+
models: {
|
|
244
|
+
[import_ai_manager.SupportedModel.LLM]: [
|
|
245
|
+
"mistral-large-latest",
|
|
246
|
+
"mistral-medium-latest",
|
|
247
|
+
"mistral-medium-3-5",
|
|
248
|
+
"mistral-small-latest",
|
|
249
|
+
"ministral-8b-latest",
|
|
250
|
+
"ministral-3b-latest",
|
|
251
|
+
"codestral-latest",
|
|
252
|
+
"pixtral-large-latest"
|
|
253
|
+
],
|
|
254
|
+
[import_ai_manager.SupportedModel.EMBEDDING]: ["mistral-embed"]
|
|
255
|
+
},
|
|
256
|
+
provider: MistralProvider,
|
|
257
|
+
embedding: MistralEmbeddingProvider
|
|
258
|
+
};
|
|
259
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
260
|
+
0 && (module.exports = {
|
|
261
|
+
MistralEmbeddingProvider,
|
|
262
|
+
MistralProvider,
|
|
263
|
+
injectMistralReasoningEffort,
|
|
264
|
+
mistralProviderOptions
|
|
265
|
+
});
|
|
@@ -10,9 +10,9 @@ import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
|
10
10
|
import { Model } from '@nocobase/database';
|
|
11
11
|
import { AttachmentModel } from '@nocobase/plugin-file-manager';
|
|
12
12
|
import { Application } from '@nocobase/server';
|
|
13
|
-
import { AIChatContext } from '../types/ai-chat-conversation.type';
|
|
13
|
+
import { AIChatContext, AIMessageInput } from '../types/ai-chat-conversation.type';
|
|
14
14
|
import { EmbeddingsInterface } from '@langchain/core/embeddings';
|
|
15
|
-
import { AIMessageChunk } from '@langchain/core/messages';
|
|
15
|
+
import { AIMessage, AIMessageChunk } from '@langchain/core/messages';
|
|
16
16
|
import { Context } from '@nocobase/actions';
|
|
17
17
|
import '@langchain/core/utils/stream';
|
|
18
18
|
import { LLMResult } from '@langchain/core/outputs';
|
|
@@ -90,6 +90,10 @@ export declare abstract class LLMProvider {
|
|
|
90
90
|
} | null;
|
|
91
91
|
parseResponseMetadata(output: LLMResult): any;
|
|
92
92
|
parseResponseError(err: any): any;
|
|
93
|
+
reshapeAIMessage(_options: {
|
|
94
|
+
aiMessage: AIMessage;
|
|
95
|
+
values: AIMessageInput;
|
|
96
|
+
}): void;
|
|
93
97
|
protected get documentLoader(): CachedDocumentLoader;
|
|
94
98
|
protected getResolvedBaseURL(): string;
|
|
95
99
|
protected buildRequestURL(pathname: string): string;
|
|
@@ -46,15 +46,34 @@ var import_stream = require("@langchain/core/utils/stream");
|
|
|
46
46
|
var import_document_loader = require("../document-loader");
|
|
47
47
|
var import_node_path = __toESM(require("node:path"));
|
|
48
48
|
var import_reasoning = require("./common/reasoning");
|
|
49
|
+
function assertBaseURLString(baseURL) {
|
|
50
|
+
if (typeof baseURL !== "string") {
|
|
51
|
+
throw new Error("baseURL must be a string");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
49
54
|
function normalizeBaseURL(baseURL) {
|
|
50
|
-
(
|
|
51
|
-
|
|
55
|
+
assertBaseURLString(baseURL);
|
|
56
|
+
const trimmedBaseURL = baseURL.trim();
|
|
57
|
+
(0, import_utils.checkUrlAgainstWhitelist)(trimmedBaseURL);
|
|
58
|
+
return new URL(trimmedBaseURL).toString().replace(/\/$/, "");
|
|
59
|
+
}
|
|
60
|
+
function isBlankBaseURL(baseURL) {
|
|
61
|
+
return baseURL.trim() === "";
|
|
62
|
+
}
|
|
63
|
+
function getServiceBaseURL(serviceOptions) {
|
|
64
|
+
const baseURL = serviceOptions == null ? void 0 : serviceOptions.baseURL;
|
|
65
|
+
if (typeof baseURL === "string" && isBlankBaseURL(baseURL)) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return baseURL;
|
|
52
69
|
}
|
|
53
70
|
function resolveServiceOptions(serviceOptions, app) {
|
|
54
71
|
const rendered = app.environment.renderJsonTemplate(serviceOptions ?? {});
|
|
55
72
|
if ((rendered == null ? void 0 : rendered.baseURL) != null) {
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
assertBaseURLString(rendered.baseURL);
|
|
74
|
+
if (isBlankBaseURL(rendered.baseURL)) {
|
|
75
|
+
delete rendered.baseURL;
|
|
76
|
+
return rendered;
|
|
58
77
|
}
|
|
59
78
|
rendered.baseURL = normalizeBaseURL(rendered.baseURL);
|
|
60
79
|
}
|
|
@@ -319,18 +338,16 @@ ${parsed.text}
|
|
|
319
338
|
parseResponseError(err) {
|
|
320
339
|
return (err == null ? void 0 : err.message) ?? "Unexpected LLM service error";
|
|
321
340
|
}
|
|
341
|
+
reshapeAIMessage(_options) {
|
|
342
|
+
}
|
|
322
343
|
get documentLoader() {
|
|
323
344
|
return this.aiPlugin.documentLoaders.cached;
|
|
324
345
|
}
|
|
325
346
|
getResolvedBaseURL() {
|
|
326
|
-
|
|
327
|
-
const baseURL = ((_a = this.serviceOptions) == null ? void 0 : _a.baseURL) ?? this.baseURL;
|
|
347
|
+
const baseURL = getServiceBaseURL(this.serviceOptions) ?? this.baseURL;
|
|
328
348
|
if (!baseURL) {
|
|
329
349
|
throw new Error("baseURL is required");
|
|
330
350
|
}
|
|
331
|
-
if (typeof baseURL !== "string") {
|
|
332
|
-
throw new Error("baseURL must be a string");
|
|
333
|
-
}
|
|
334
351
|
return normalizeBaseURL(baseURL);
|
|
335
352
|
}
|
|
336
353
|
buildRequestURL(pathname) {
|
|
@@ -361,14 +378,10 @@ class EmbeddingProvider {
|
|
|
361
378
|
return apiKey;
|
|
362
379
|
}
|
|
363
380
|
get baseURL() {
|
|
364
|
-
|
|
365
|
-
const baseURL = ((_a = this.serviceOptions) == null ? void 0 : _a.baseURL) ?? this.getDefaultUrl();
|
|
381
|
+
const baseURL = getServiceBaseURL(this.serviceOptions) ?? this.getDefaultUrl();
|
|
366
382
|
if (!baseURL) {
|
|
367
383
|
throw new Error("baseURL is required");
|
|
368
384
|
}
|
|
369
|
-
if (typeof baseURL !== "string") {
|
|
370
|
-
throw new Error("baseURL must be a string");
|
|
371
|
-
}
|
|
372
385
|
return normalizeBaseURL(baseURL);
|
|
373
386
|
}
|
|
374
387
|
get model() {
|
package/dist/server/plugin.js
CHANGED
|
@@ -74,6 +74,7 @@ var import_xai = require("./llm-providers/xai");
|
|
|
74
74
|
var import_document_loader = require("./document-loader");
|
|
75
75
|
var import_checkpoints = require("./ai-employees/checkpoints");
|
|
76
76
|
var import_mimo = require("./llm-providers/mimo");
|
|
77
|
+
var import_mistral = require("./llm-providers/mistral");
|
|
77
78
|
var import_sub_agents = require("./ai-employees/sub-agents");
|
|
78
79
|
var import_employee = require("./workflow/nodes/employee");
|
|
79
80
|
var import_ai_knowledge_base = require("./ai-employees/ai-knowledge-base");
|
|
@@ -180,6 +181,7 @@ class PluginAIServer extends import_server.Plugin {
|
|
|
180
181
|
this.aiManager.registerLLMProvider("dashscope", import_dashscope.dashscopeProviderOptions);
|
|
181
182
|
this.aiManager.registerLLMProvider("kimi", import_kimi.kimiProviderOptions);
|
|
182
183
|
this.aiManager.registerLLMProvider("mimo", import_mimo.mimoProviderOptions);
|
|
184
|
+
this.aiManager.registerLLMProvider("mistral", import_mistral.mistralProviderOptions);
|
|
183
185
|
this.aiManager.registerLLMProvider("ollama", import_ollama.ollamaProviderOptions);
|
|
184
186
|
this.aiManager.registerLLMProvider("openai-completions", import_openai2.openaiCompletionsProviderOptions);
|
|
185
187
|
this.aiManager.registerLLMProvider("kimi", import_kimi.kimiProviderOptions);
|
|
@@ -120,27 +120,29 @@ ${typeof message.system === "object" ? JSON.stringify(message.system) : message.
|
|
|
120
120
|
});
|
|
121
121
|
const plugin = this.workflow.app.pm.get("ai");
|
|
122
122
|
const resolvedModel = await plugin.aiEmployeesManager.resolveModel(employee, model);
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
user:
|
|
132
|
-
id: ((_e = (_d = input == null ? void 0 : input.result) == null ? void 0 : _d.user) == null ? void 0 : _e.id) ?? userId
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
action: {
|
|
136
|
-
params: {
|
|
137
|
-
values: {
|
|
138
|
-
sessionId: conversation.sessionId,
|
|
139
|
-
model: resolvedModel
|
|
140
|
-
}
|
|
141
|
-
}
|
|
123
|
+
const aiEmployeeContext = {
|
|
124
|
+
app: this.workflow.app,
|
|
125
|
+
db: this.workflow.app.db,
|
|
126
|
+
log: this.workflow.app.log,
|
|
127
|
+
logger: this.workflow.app.log,
|
|
128
|
+
state: { currentRoles },
|
|
129
|
+
auth: {
|
|
130
|
+
user: {
|
|
131
|
+
id: ((_e = (_d = input == null ? void 0 : input.result) == null ? void 0 : _d.user) == null ? void 0 : _e.id) ?? userId
|
|
142
132
|
}
|
|
143
133
|
},
|
|
134
|
+
action: {
|
|
135
|
+
params: {
|
|
136
|
+
values: {
|
|
137
|
+
sessionId: conversation.sessionId,
|
|
138
|
+
model: resolvedModel
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const aiEmployeeActionValues = aiEmployeeContext.action.params.values;
|
|
144
|
+
const aiEmployee = new import_ai_employee.AIEmployee({
|
|
145
|
+
ctx: aiEmployeeContext,
|
|
144
146
|
employee,
|
|
145
147
|
sessionId: conversation.sessionId,
|
|
146
148
|
systemMessage,
|
|
@@ -158,6 +160,7 @@ ${typeof message.system === "object" ? JSON.stringify(message.system) : message.
|
|
|
158
160
|
}
|
|
159
161
|
let result;
|
|
160
162
|
let isToolInvoke = false;
|
|
163
|
+
let recoveredFromGraphRecursion = false;
|
|
161
164
|
let retry = 0;
|
|
162
165
|
do {
|
|
163
166
|
const userMessages = [
|
|
@@ -170,36 +173,76 @@ ${typeof message.system === "object" ? JSON.stringify(message.system) : message.
|
|
|
170
173
|
...attachmentPart
|
|
171
174
|
}
|
|
172
175
|
];
|
|
173
|
-
|
|
174
|
-
if (retry
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
176
|
+
try {
|
|
177
|
+
if (retry > 0) {
|
|
178
|
+
if (retry < 2) {
|
|
179
|
+
abortHandle.throwIfAborted();
|
|
180
|
+
const firstUserMessage = await this.workflow.db.getRepository("aiConversations.messages", conversation.sessionId).findOne({
|
|
181
|
+
filter: {
|
|
182
|
+
role: "user"
|
|
183
|
+
},
|
|
184
|
+
sort: ["messageId"]
|
|
185
|
+
});
|
|
186
|
+
const messageId = firstUserMessage == null ? void 0 : firstUserMessage.messageId;
|
|
187
|
+
result = await aiEmployee.invoke({ messageId, userMessages, signal: abortHandle.signal });
|
|
188
|
+
} else {
|
|
189
|
+
result = await aiEmployee.invoke({
|
|
190
|
+
signal: abortHandle.signal,
|
|
191
|
+
userMessages: [
|
|
192
|
+
{
|
|
193
|
+
role: "user",
|
|
194
|
+
content: {
|
|
195
|
+
type: "text",
|
|
196
|
+
content: `You failed to call the required tool "${toolName}" in your previous response.
|
|
197
|
+
Call "${toolName}" now to submit the workflow outcome.
|
|
194
198
|
Do not send another normal assistant response without invoking it.
|
|
195
199
|
`
|
|
200
|
+
}
|
|
196
201
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
202
|
+
]
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
result = await aiEmployee.invoke({ userMessages, signal: abortHandle.signal });
|
|
200
207
|
}
|
|
201
|
-
}
|
|
202
|
-
|
|
208
|
+
} catch (error) {
|
|
209
|
+
if (!isGraphRecursionError(error) || recoveredFromGraphRecursion) {
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
recoveredFromGraphRecursion = true;
|
|
213
|
+
processor.logger.warn(`ai employee invoke reached graph recursion limit, trying workflow output recovery`, {
|
|
214
|
+
node: node.id,
|
|
215
|
+
stack: error.stack,
|
|
216
|
+
chatOptions: node.config
|
|
217
|
+
});
|
|
218
|
+
const latestMessage = await this.workflow.db.getRepository("aiConversations.messages", conversation.sessionId).findOne({
|
|
219
|
+
sort: ["-messageId"]
|
|
220
|
+
});
|
|
221
|
+
const recoveryAIEmployee = new import_ai_employee.AIEmployee({
|
|
222
|
+
ctx: {
|
|
223
|
+
...aiEmployeeContext,
|
|
224
|
+
action: {
|
|
225
|
+
params: {
|
|
226
|
+
values: {
|
|
227
|
+
...aiEmployeeActionValues,
|
|
228
|
+
important: "GraphRecursionError"
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
employee,
|
|
234
|
+
sessionId: conversation.sessionId,
|
|
235
|
+
systemMessage,
|
|
236
|
+
skillSettings,
|
|
237
|
+
webSearch,
|
|
238
|
+
model: resolvedModel,
|
|
239
|
+
tools: [{ name: toolName }]
|
|
240
|
+
});
|
|
241
|
+
abortHandle.throwIfAborted();
|
|
242
|
+
result = await recoveryAIEmployee.invoke({
|
|
243
|
+
messageId: latestMessage == null ? void 0 : latestMessage.messageId,
|
|
244
|
+
signal: abortHandle.signal
|
|
245
|
+
});
|
|
203
246
|
}
|
|
204
247
|
abortHandle.throwIfAborted();
|
|
205
248
|
isToolInvoke = result.messages.filter((it) => it.type === "ai").flatMap((it) => it.tool_calls).some((it) => it.name === toolName);
|
|
@@ -270,7 +313,7 @@ Do not send another normal assistant response without invoking it.
|
|
|
270
313
|
username
|
|
271
314
|
},
|
|
272
315
|
title: userMessage.slice(0, 30),
|
|
273
|
-
from: "
|
|
316
|
+
from: "main-agent",
|
|
274
317
|
options: {
|
|
275
318
|
systemMessage,
|
|
276
319
|
skillSettings,
|
|
@@ -464,6 +507,9 @@ async function parseAssignees(node, processor) {
|
|
|
464
507
|
}
|
|
465
508
|
return assignees;
|
|
466
509
|
}
|
|
510
|
+
function isGraphRecursionError(error) {
|
|
511
|
+
return typeof error === "object" && error !== null && ("name" in error || "lc_error_code" in error) && (error.name === "GraphRecursionError" || error.lc_error_code === "GRAPH_RECURSION_LIMIT");
|
|
512
|
+
}
|
|
467
513
|
// Annotate the CommonJS export names for ESM import in node:
|
|
468
514
|
0 && (module.exports = {
|
|
469
515
|
AIEmployeeInstruction,
|
|
@@ -29,6 +29,7 @@ __export(tools_exports, {
|
|
|
29
29
|
getWorkflowTasks: () => getWorkflowTasks
|
|
30
30
|
});
|
|
31
31
|
module.exports = __toCommonJS(tools_exports);
|
|
32
|
+
var import_singletons = require("@langchain/core/singletons");
|
|
32
33
|
var import_plugin_workflow = require("@nocobase/plugin-workflow");
|
|
33
34
|
var import_constants = require("./constants");
|
|
34
35
|
const getWorkflowTasks = (plugin) => async (register, filter) => {
|
|
@@ -141,7 +142,13 @@ const getWorkflowTasks = (plugin) => async (register, filter) => {
|
|
|
141
142
|
status: import_plugin_workflow.JOB_STATUS.RESOLVED,
|
|
142
143
|
result: args.result
|
|
143
144
|
});
|
|
144
|
-
|
|
145
|
+
setImmediate(() => {
|
|
146
|
+
import_singletons.AsyncLocalStorageProviderSingleton.getInstance().run(void 0, () => {
|
|
147
|
+
workflowPlugin.resume(job).catch((error) => {
|
|
148
|
+
plugin.app.logger.error(error);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
145
152
|
return {
|
|
146
153
|
status: "success"
|
|
147
154
|
};
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"description": "Create AI employees with diverse skills to collaborate with humans, build systems, and handle business operations.",
|
|
7
7
|
"description.ru-RU": "Поддержка интеграции с AI-сервисами: предоставляются AI-узлы для рабочих процессов, расширяя возможности бизнес-обработки.",
|
|
8
8
|
"description.zh-CN": "创建各种技能的 AI 员工,与人类协同,搭建系统,处理业务。",
|
|
9
|
-
"version": "2.2.0-beta.
|
|
9
|
+
"version": "2.2.0-beta.9",
|
|
10
10
|
"main": "dist/server/index.js",
|
|
11
11
|
"homepage": "https://docs.nocobase.com/handbook/action-ai",
|
|
12
12
|
"homepage.ru-RU": "https://docs-ru.nocobase.com/handbook/action-ai",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"@langchain/google-genai": "2.1.18",
|
|
42
42
|
"@langchain/langgraph": "1.4.4",
|
|
43
43
|
"@langchain/langgraph-checkpoint": "1.1.2",
|
|
44
|
+
"@langchain/mistralai": "1.0.0",
|
|
44
45
|
"@langchain/ollama": "1.2.7",
|
|
45
46
|
"@langchain/openai": "1.4.7",
|
|
46
47
|
"@langchain/xai": "1.3.19",
|
|
@@ -65,5 +66,5 @@
|
|
|
65
66
|
"keywords": [
|
|
66
67
|
"AI"
|
|
67
68
|
],
|
|
68
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "60e3d7abbaa0c7cead76f71a4f3d5eedb6b8acdb"
|
|
69
70
|
}
|