@nocobase/plugin-ai 2.2.0-alpha.5 → 2.2.0-alpha.7
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/file-manager/storage/local.md +3 -1
- package/dist/ai/docs/nocobase/get-started/installation/docker-caddy.mdx +6 -1
- package/dist/ai/docs/nocobase/get-started/installation/docker-nginx.mdx +6 -2
- package/dist/ai/docs/nocobase/get-started/installation/docker.mdx +94 -1
- package/dist/ai/docs/nocobase/security/guide.md +23 -0
- package/dist/ai/tools/subAgentWebSearch.js +20 -15
- package/dist/client/index.js +1 -1
- package/dist/client-v2/ai-employees/tools/data-modeling/useFieldInterfaceOptions.d.ts +1 -0
- package/dist/client-v2/index.js +1 -1
- package/dist/client-v2/llm-providers/forms.d.ts +2 -0
- package/dist/client-v2/llm-providers/index.d.ts +1 -0
- package/dist/externalVersion.js +15 -15
- package/dist/locale/en-US.json +5 -0
- package/dist/locale/zh-CN.json +5 -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.js +2 -1
- package/dist/server/ai-employees/prompts.d.ts +2 -1
- package/dist/server/ai-employees/prompts.js +8 -2
- package/dist/server/collections/ai-usage-events.d.ts +10 -0
- package/dist/server/collections/ai-usage-events.js +183 -0
- package/dist/server/llm-providers/dashscope.d.ts +2 -1
- package/dist/server/llm-providers/dashscope.js +16 -1
- package/dist/server/llm-providers/deepseek.d.ts +2 -1
- package/dist/server/llm-providers/deepseek.js +33 -2
- package/dist/server/llm-providers/kimi/provider.d.ts +2 -1
- package/dist/server/llm-providers/kimi/provider.js +22 -2
- package/dist/server/llm-providers/mistral.d.ts +36 -2
- package/dist/server/llm-providers/mistral.js +62 -2
- package/dist/server/llm-providers/openai/completions.d.ts +2 -1
- package/dist/server/llm-providers/openai/completions.js +17 -1
- package/dist/server/llm-providers/openai/responses.d.ts +2 -1
- package/dist/server/llm-providers/openai/responses.js +17 -1
- package/dist/server/llm-providers/orcarouter.d.ts +35 -0
- package/dist/server/llm-providers/orcarouter.js +155 -0
- package/dist/server/llm-providers/provider.d.ts +7 -0
- package/dist/server/llm-providers/provider.js +7 -1
- package/dist/server/manager/ai-chat-conversation.js +2 -0
- package/dist/server/manager/ai-manager.d.ts +2 -1
- package/dist/server/manager/ai-manager.js +4 -1
- package/dist/server/manager/ai-usage-events.d.ts +49 -0
- package/dist/server/manager/ai-usage-events.js +195 -0
- package/dist/server/plugin.js +2 -0
- package/package.json +2 -2
|
@@ -45,6 +45,7 @@ var import_provider = require("./provider");
|
|
|
45
45
|
var import_ai_manager = require("../manager/ai-manager");
|
|
46
46
|
var import_lodash = __toESM(require("lodash"));
|
|
47
47
|
var import_reasoning = require("./common/reasoning");
|
|
48
|
+
const DEEPSEEK_REASONING_EFFORTS = /* @__PURE__ */ new Set(["low", "medium", "high"]);
|
|
48
49
|
class ReasoningDeepSeek extends import_deepseek.ChatDeepSeek {
|
|
49
50
|
async _generate(messages, options, runManager) {
|
|
50
51
|
const reasoningMap = (0, import_reasoning.collectReasoningMap)(messages);
|
|
@@ -80,6 +81,7 @@ class DeepSeekProvider extends import_provider.LLMProvider {
|
|
|
80
81
|
createModel() {
|
|
81
82
|
const { apiKey } = this.serviceOptions || {};
|
|
82
83
|
const { responseFormat } = this.modelOptions || {};
|
|
84
|
+
const reasoningOptions = this.resolveReasoningOptions(this.modelReasoningOptions);
|
|
83
85
|
const modelKwargs = {};
|
|
84
86
|
if (responseFormat) {
|
|
85
87
|
modelKwargs["response_format"] = {
|
|
@@ -89,7 +91,11 @@ class DeepSeekProvider extends import_provider.LLMProvider {
|
|
|
89
91
|
return new ReasoningDeepSeek({
|
|
90
92
|
apiKey,
|
|
91
93
|
...this.modelOptions,
|
|
92
|
-
|
|
94
|
+
...reasoningOptions.modelRequestParams || {},
|
|
95
|
+
modelKwargs: {
|
|
96
|
+
...modelKwargs,
|
|
97
|
+
...reasoningOptions.modelKwargs || {}
|
|
98
|
+
},
|
|
93
99
|
configuration: {
|
|
94
100
|
baseURL: this.getResolvedBaseURL()
|
|
95
101
|
},
|
|
@@ -124,6 +130,31 @@ class DeepSeekProvider extends import_provider.LLMProvider {
|
|
|
124
130
|
}
|
|
125
131
|
return null;
|
|
126
132
|
}
|
|
133
|
+
resolveReasoningOptions(reasoning) {
|
|
134
|
+
if (!reasoning || reasoning.mode === "default") {
|
|
135
|
+
return {};
|
|
136
|
+
}
|
|
137
|
+
if (reasoning.mode === "off") {
|
|
138
|
+
return {
|
|
139
|
+
modelKwargs: {
|
|
140
|
+
thinking: {
|
|
141
|
+
type: "disabled"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (!DEEPSEEK_REASONING_EFFORTS.has(reasoning.mode)) {
|
|
147
|
+
return {};
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
modelKwargs: {
|
|
151
|
+
thinking: {
|
|
152
|
+
type: "enabled"
|
|
153
|
+
},
|
|
154
|
+
reasoning_effort: reasoning.mode
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
127
158
|
isApiSupportedAttachment(attachment) {
|
|
128
159
|
return false;
|
|
129
160
|
}
|
|
@@ -132,7 +163,7 @@ const deepseekProviderOptions = {
|
|
|
132
163
|
title: "DeepSeek",
|
|
133
164
|
supportedModel: [import_ai_manager.SupportedModel.LLM],
|
|
134
165
|
models: {
|
|
135
|
-
[import_ai_manager.SupportedModel.LLM]: ["deepseek-chat", "deepseek-reasoner"]
|
|
166
|
+
[import_ai_manager.SupportedModel.LLM]: ["deepseek-v4-pro", "deepseek-v4-flash", "deepseek-chat", "deepseek-reasoner"]
|
|
136
167
|
},
|
|
137
168
|
provider: DeepSeekProvider
|
|
138
169
|
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { AIMessageChunk } from '@langchain/core/messages';
|
|
10
10
|
import { Model } from '@nocobase/database';
|
|
11
|
-
import { LLMProvider } from '../provider';
|
|
11
|
+
import { LLMProvider, ReasoningOptions, ResolvedReasoningOptions } from '../provider';
|
|
12
12
|
import { LLMProviderMeta } from '../../manager/ai-manager';
|
|
13
13
|
import { CachedDocumentLoader } from '../../document-loader';
|
|
14
14
|
import { ReasoningChatOpenAI } from '../common/reasoning';
|
|
@@ -28,6 +28,7 @@ export declare class KimiProvider extends LLMProvider {
|
|
|
28
28
|
status: string;
|
|
29
29
|
content: string;
|
|
30
30
|
};
|
|
31
|
+
protected resolveReasoningOptions(reasoning?: ReasoningOptions): ResolvedReasoningOptions;
|
|
31
32
|
protected isApiSupportedAttachment(attachment: AttachmentModel): boolean;
|
|
32
33
|
protected get documentLoader(): CachedDocumentLoader;
|
|
33
34
|
}
|
|
@@ -46,6 +46,7 @@ var import_ai_manager = require("../../manager/ai-manager");
|
|
|
46
46
|
var import_document_loader = require("../../document-loader");
|
|
47
47
|
var import_document_loader2 = require("./document-loader");
|
|
48
48
|
var import_reasoning = require("../common/reasoning");
|
|
49
|
+
const KIMI_THINKING_SWITCH_MODELS = /* @__PURE__ */ new Set(["kimi-k2.5", "kimi-k2.6"]);
|
|
49
50
|
class KimiProvider extends import_provider.LLMProvider {
|
|
50
51
|
_documentLoader;
|
|
51
52
|
get baseURL() {
|
|
@@ -55,6 +56,7 @@ class KimiProvider extends import_provider.LLMProvider {
|
|
|
55
56
|
const { apiKey } = this.serviceOptions || {};
|
|
56
57
|
const { responseFormat, structuredOutput } = this.modelOptions || {};
|
|
57
58
|
const { name, schema } = structuredOutput || {};
|
|
59
|
+
const reasoningOptions = this.resolveReasoningOptions(this.modelReasoningOptions);
|
|
58
60
|
const responseFormatOptions = {
|
|
59
61
|
type: responseFormat ?? "text"
|
|
60
62
|
};
|
|
@@ -65,8 +67,10 @@ class KimiProvider extends import_provider.LLMProvider {
|
|
|
65
67
|
apiKey,
|
|
66
68
|
...this.modelOptions,
|
|
67
69
|
modelKwargs: {
|
|
68
|
-
response_format: responseFormatOptions
|
|
70
|
+
response_format: responseFormatOptions,
|
|
71
|
+
...reasoningOptions.modelKwargs || {}
|
|
69
72
|
},
|
|
73
|
+
...reasoningOptions.modelRequestParams || {},
|
|
70
74
|
configuration: {
|
|
71
75
|
baseURL: this.getResolvedBaseURL()
|
|
72
76
|
}
|
|
@@ -100,6 +104,22 @@ class KimiProvider extends import_provider.LLMProvider {
|
|
|
100
104
|
}
|
|
101
105
|
return null;
|
|
102
106
|
}
|
|
107
|
+
resolveReasoningOptions(reasoning) {
|
|
108
|
+
var _a;
|
|
109
|
+
if (!reasoning || reasoning.mode === "default") {
|
|
110
|
+
return {};
|
|
111
|
+
}
|
|
112
|
+
if (!KIMI_THINKING_SWITCH_MODELS.has((_a = this.modelOptions) == null ? void 0 : _a.model)) {
|
|
113
|
+
return {};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
modelKwargs: {
|
|
117
|
+
thinking: {
|
|
118
|
+
type: reasoning.mode === "off" ? "disabled" : "enabled"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
103
123
|
isApiSupportedAttachment(attachment) {
|
|
104
124
|
var _a;
|
|
105
125
|
return ((_a = attachment.mimetype) == null ? void 0 : _a.startsWith("image/")) ?? false;
|
|
@@ -126,7 +146,7 @@ const kimiProviderOptions = {
|
|
|
126
146
|
title: "Kimi",
|
|
127
147
|
supportedModel: [import_ai_manager.SupportedModel.LLM],
|
|
128
148
|
models: {
|
|
129
|
-
[import_ai_manager.SupportedModel.LLM]: ["kimi-k2.
|
|
149
|
+
[import_ai_manager.SupportedModel.LLM]: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2.5"]
|
|
130
150
|
},
|
|
131
151
|
provider: KimiProvider
|
|
132
152
|
};
|
|
@@ -10,21 +10,55 @@ import { EmbeddingsInterface } from '@langchain/core/embeddings';
|
|
|
10
10
|
import { AIMessage, AIMessageChunk } from '@langchain/core/messages';
|
|
11
11
|
import { ChatMistralAI } from '@langchain/mistralai';
|
|
12
12
|
import { AttachmentModel } from '@nocobase/plugin-file-manager';
|
|
13
|
-
import { EmbeddingProvider, LLMProvider, LLMProviderInvokeOptions } from './provider';
|
|
13
|
+
import { EmbeddingProvider, LLMProvider, LLMProviderInvokeOptions, ReasoningMode, ReasoningOptions, ResolvedReasoningOptions } from './provider';
|
|
14
14
|
import { LLMProviderMeta } from '../manager/ai-manager';
|
|
15
15
|
import { AIChatContext, AIMessageInput } from '../types/ai-chat-conversation.type';
|
|
16
16
|
import { Model } from '@nocobase/database';
|
|
17
|
+
declare const MISTRAL_REASONING_MODE_KEY = "__nb_reasoning_mode";
|
|
17
18
|
type MistralCallOptions = LLMProviderInvokeOptions & {
|
|
18
19
|
response_format?: {
|
|
19
20
|
type: 'text' | 'json_object';
|
|
20
21
|
};
|
|
21
22
|
};
|
|
22
23
|
type MistralBeforeRequestHook = (request: Request) => Request | void | Promise<Request | void>;
|
|
24
|
+
type ReasoningChatMistralAIFields = ConstructorParameters<typeof ChatMistralAI>[0] & {
|
|
25
|
+
[MISTRAL_REASONING_MODE_KEY]?: ReasoningMode;
|
|
26
|
+
};
|
|
23
27
|
export declare const injectMistralReasoningEffort: MistralBeforeRequestHook;
|
|
28
|
+
declare class ReasoningChatMistralAI extends ChatMistralAI {
|
|
29
|
+
private readonly reasoningMode?;
|
|
30
|
+
constructor(fields: ReasoningChatMistralAIFields);
|
|
31
|
+
invocationParams(options?: MistralCallOptions): Omit<import("@mistralai/mistralai/models/components/chatcompletionrequest").ChatCompletionRequest | import("@mistralai/mistralai/models/components/chatcompletionstreamrequest").ChatCompletionStreamRequest, "messages"> | {
|
|
32
|
+
__nb_reasoning_mode: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
33
|
+
model: string;
|
|
34
|
+
tools?: import("@mistralai/mistralai/models/components/tool").Tool[];
|
|
35
|
+
metadata?: {
|
|
36
|
+
[k: string]: any;
|
|
37
|
+
} | {
|
|
38
|
+
[k: string]: any;
|
|
39
|
+
};
|
|
40
|
+
stream?: boolean;
|
|
41
|
+
responseFormat?: import("@mistralai/mistralai/models/components/responseformat").ResponseFormat;
|
|
42
|
+
temperature?: number;
|
|
43
|
+
maxTokens?: number;
|
|
44
|
+
topP?: number;
|
|
45
|
+
frequencyPenalty?: number;
|
|
46
|
+
presencePenalty?: number;
|
|
47
|
+
n?: number;
|
|
48
|
+
stop?: string | string[];
|
|
49
|
+
toolChoice?: import("@mistralai/mistralai/models/components/toolchoice").ToolChoice | import("@mistralai/mistralai/models/components/toolchoiceenum").ToolChoiceEnum;
|
|
50
|
+
randomSeed?: number;
|
|
51
|
+
prediction?: import("@mistralai/mistralai/models/components/prediction").Prediction;
|
|
52
|
+
parallelToolCalls?: boolean;
|
|
53
|
+
promptMode?: import("@mistralai/mistralai/models/components/mistralpromptmode").MistralPromptMode;
|
|
54
|
+
safePrompt?: boolean;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
24
57
|
export declare class MistralProvider extends LLMProvider {
|
|
25
58
|
chatModel: ChatMistralAI;
|
|
26
59
|
get baseURL(): string;
|
|
27
|
-
createModel():
|
|
60
|
+
createModel(): ReasoningChatMistralAI;
|
|
61
|
+
protected resolveReasoningOptions(reasoning?: ReasoningOptions): ResolvedReasoningOptions;
|
|
28
62
|
stream(context: AIChatContext, options?: MistralCallOptions): Promise<any>;
|
|
29
63
|
invoke(context: AIChatContext, options?: MistralCallOptions): Promise<any>;
|
|
30
64
|
listModels(): Promise<{
|
|
@@ -39,6 +39,8 @@ var import_ai_manager = require("../manager/ai-manager");
|
|
|
39
39
|
const MISTRAL_URL = "https://api.mistral.ai";
|
|
40
40
|
const MISTRAL_REASONING_EFFORT = "high";
|
|
41
41
|
const MISTRAL_REASONING_MODELS = /* @__PURE__ */ new Set(["mistral-small-latest", "mistral-medium-3-5"]);
|
|
42
|
+
const MISTRAL_REASONING_EFFORTS = /* @__PURE__ */ new Set(["off", "low", "medium", "high"]);
|
|
43
|
+
const MISTRAL_REASONING_MODE_KEY = "__nb_reasoning_mode";
|
|
42
44
|
function omitDisabledNumberOptions(options) {
|
|
43
45
|
for (const key of ["maxTokens", "maxRetries"]) {
|
|
44
46
|
if (options[key] === -1) {
|
|
@@ -73,19 +75,62 @@ const injectMistralReasoningEffort = async (request) => {
|
|
|
73
75
|
if (!body || typeof body !== "object") {
|
|
74
76
|
return;
|
|
75
77
|
}
|
|
78
|
+
const reasoningMode = body[MISTRAL_REASONING_MODE_KEY];
|
|
79
|
+
delete body[MISTRAL_REASONING_MODE_KEY];
|
|
80
|
+
const shouldRewriteBody = reasoningMode != null;
|
|
76
81
|
if (typeof body.model !== "string" || !MISTRAL_REASONING_MODELS.has(body.model)) {
|
|
82
|
+
if (shouldRewriteBody) {
|
|
83
|
+
const headers2 = new Headers(request.headers);
|
|
84
|
+
headers2.delete("content-length");
|
|
85
|
+
return new Request(request, {
|
|
86
|
+
headers: headers2,
|
|
87
|
+
body: JSON.stringify(body)
|
|
88
|
+
});
|
|
89
|
+
}
|
|
77
90
|
return;
|
|
78
91
|
}
|
|
92
|
+
if (reasoningMode === "off") {
|
|
93
|
+
delete body.reasoning_effort;
|
|
94
|
+
const headers2 = new Headers(request.headers);
|
|
95
|
+
headers2.delete("content-length");
|
|
96
|
+
return new Request(request, {
|
|
97
|
+
headers: headers2,
|
|
98
|
+
body: JSON.stringify(body)
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (body.reasoning_effort && !shouldRewriteBody) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const reasoningEffort = reasoningMode && reasoningMode !== "default" ? reasoningMode : MISTRAL_REASONING_EFFORT;
|
|
79
105
|
const headers = new Headers(request.headers);
|
|
80
106
|
headers.delete("content-length");
|
|
81
107
|
return new Request(request, {
|
|
82
108
|
headers,
|
|
83
109
|
body: JSON.stringify({
|
|
84
110
|
...body,
|
|
85
|
-
reasoning_effort:
|
|
111
|
+
reasoning_effort: reasoningEffort
|
|
86
112
|
})
|
|
87
113
|
});
|
|
88
114
|
};
|
|
115
|
+
class ReasoningChatMistralAI extends import_mistralai.ChatMistralAI {
|
|
116
|
+
reasoningMode;
|
|
117
|
+
constructor(fields) {
|
|
118
|
+
const { [MISTRAL_REASONING_MODE_KEY]: reasoningMode, ...modelFields } = fields;
|
|
119
|
+
super(modelFields);
|
|
120
|
+
this.reasoningMode = reasoningMode;
|
|
121
|
+
}
|
|
122
|
+
invocationParams(options) {
|
|
123
|
+
const params = super.invocationParams(options);
|
|
124
|
+
const mode = this.reasoningMode;
|
|
125
|
+
if (!mode || mode === "default") {
|
|
126
|
+
return params;
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
...params,
|
|
130
|
+
[MISTRAL_REASONING_MODE_KEY]: mode
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
89
134
|
class MistralProvider extends import_provider.LLMProvider {
|
|
90
135
|
get baseURL() {
|
|
91
136
|
return MISTRAL_URL;
|
|
@@ -95,14 +140,29 @@ class MistralProvider extends import_provider.LLMProvider {
|
|
|
95
140
|
const { responseFormat, structuredOutput, ...modelOptions } = this.modelOptions || {};
|
|
96
141
|
omitDisabledNumberOptions(modelOptions);
|
|
97
142
|
const beforeRequestHooks = Array.isArray(modelOptions.beforeRequestHooks) ? [injectMistralReasoningEffort, ...modelOptions.beforeRequestHooks] : [injectMistralReasoningEffort];
|
|
98
|
-
|
|
143
|
+
const reasoningOptions = this.resolveReasoningOptions(this.modelReasoningOptions);
|
|
144
|
+
return new ReasoningChatMistralAI({
|
|
99
145
|
apiKey,
|
|
100
146
|
...modelOptions,
|
|
147
|
+
...reasoningOptions.modelRequestParams || {},
|
|
101
148
|
beforeRequestHooks,
|
|
102
149
|
serverURL: this.getResolvedServerURL(),
|
|
103
150
|
verbose: false
|
|
104
151
|
});
|
|
105
152
|
}
|
|
153
|
+
resolveReasoningOptions(reasoning) {
|
|
154
|
+
if (!reasoning || reasoning.mode === "default") {
|
|
155
|
+
return {};
|
|
156
|
+
}
|
|
157
|
+
if (!MISTRAL_REASONING_EFFORTS.has(reasoning.mode)) {
|
|
158
|
+
return {};
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
modelRequestParams: {
|
|
162
|
+
[MISTRAL_REASONING_MODE_KEY]: reasoning.mode
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
106
166
|
async stream(context, options) {
|
|
107
167
|
return super.stream(context, this.withResponseFormat(options));
|
|
108
168
|
}
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { ChatOpenAI } from '@langchain/openai';
|
|
10
|
-
import { LLMProvider } from '../provider';
|
|
10
|
+
import { LLMProvider, ReasoningOptions, ResolvedReasoningOptions } from '../provider';
|
|
11
11
|
export declare class OpenAICompletionsProvider extends LLMProvider {
|
|
12
12
|
chatModel: ChatOpenAI;
|
|
13
13
|
get baseURL(): string;
|
|
14
14
|
createModel(): ChatOpenAI<import("@langchain/openai/dist/chat_models/index.cjs").ChatOpenAICallOptions>;
|
|
15
|
+
protected resolveReasoningOptions(reasoning?: ReasoningOptions): ResolvedReasoningOptions;
|
|
15
16
|
}
|
|
@@ -39,6 +39,7 @@ class OpenAICompletionsProvider extends import_provider.LLMProvider {
|
|
|
39
39
|
const { apiKey } = this.serviceOptions || {};
|
|
40
40
|
const { responseFormat, structuredOutput } = this.modelOptions || {};
|
|
41
41
|
const { name, schema } = structuredOutput || {};
|
|
42
|
+
const reasoningOptions = this.resolveReasoningOptions(this.modelReasoningOptions);
|
|
42
43
|
const responseFormatOptions = {
|
|
43
44
|
type: responseFormat ?? "text"
|
|
44
45
|
};
|
|
@@ -48,14 +49,29 @@ class OpenAICompletionsProvider extends import_provider.LLMProvider {
|
|
|
48
49
|
return new import_openai.ChatOpenAI({
|
|
49
50
|
apiKey,
|
|
50
51
|
...this.modelOptions,
|
|
52
|
+
...reasoningOptions.modelRequestParams || {},
|
|
51
53
|
modelKwargs: {
|
|
52
|
-
response_format: responseFormatOptions
|
|
54
|
+
response_format: responseFormatOptions,
|
|
55
|
+
...reasoningOptions.modelKwargs || {}
|
|
53
56
|
},
|
|
54
57
|
configuration: {
|
|
55
58
|
baseURL: this.getResolvedBaseURL()
|
|
56
59
|
}
|
|
57
60
|
});
|
|
58
61
|
}
|
|
62
|
+
resolveReasoningOptions(reasoning) {
|
|
63
|
+
if (!reasoning || reasoning.mode === "default") {
|
|
64
|
+
return {};
|
|
65
|
+
}
|
|
66
|
+
const effort = reasoning.mode === "off" ? "none" : reasoning.mode;
|
|
67
|
+
return {
|
|
68
|
+
modelRequestParams: {
|
|
69
|
+
reasoning: {
|
|
70
|
+
effort
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
59
75
|
}
|
|
60
76
|
// Annotate the CommonJS export names for ESM import in node:
|
|
61
77
|
0 && (module.exports = {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
import { ChatOpenAI } from '@langchain/openai';
|
|
10
|
-
import { LLMProvider } from '../provider';
|
|
10
|
+
import { LLMProvider, ReasoningOptions, ResolvedReasoningOptions } from '../provider';
|
|
11
11
|
import { Model } from '@nocobase/database';
|
|
12
12
|
import { AIMessageChunk } from '@langchain/core/messages';
|
|
13
13
|
export declare class OpenAIResponsesProvider extends LLMProvider {
|
|
@@ -22,6 +22,7 @@ export declare class OpenAIResponsesProvider extends LLMProvider {
|
|
|
22
22
|
role: any;
|
|
23
23
|
};
|
|
24
24
|
protected builtInTools(): any[];
|
|
25
|
+
protected resolveReasoningOptions(reasoning?: ReasoningOptions): ResolvedReasoningOptions;
|
|
25
26
|
isToolConflict(): boolean;
|
|
26
27
|
parseWebSearchAction(chunk: AIMessageChunk): {
|
|
27
28
|
type: string;
|
|
@@ -40,6 +40,7 @@ class OpenAIResponsesProvider extends import_provider.LLMProvider {
|
|
|
40
40
|
const { apiKey } = this.serviceOptions || {};
|
|
41
41
|
const { responseFormat, structuredOutput } = this.modelOptions || {};
|
|
42
42
|
const { name, schema, strict } = structuredOutput || {};
|
|
43
|
+
const reasoningOptions = this.resolveReasoningOptions(this.modelReasoningOptions);
|
|
43
44
|
let responseFormatOptions = {
|
|
44
45
|
type: responseFormat ?? "text"
|
|
45
46
|
};
|
|
@@ -54,10 +55,12 @@ class OpenAIResponsesProvider extends import_provider.LLMProvider {
|
|
|
54
55
|
return new import_openai.ChatOpenAI({
|
|
55
56
|
apiKey,
|
|
56
57
|
...this.modelOptions,
|
|
58
|
+
...reasoningOptions.modelRequestParams || {},
|
|
57
59
|
modelKwargs: {
|
|
58
60
|
text: {
|
|
59
61
|
format: responseFormatOptions
|
|
60
|
-
}
|
|
62
|
+
},
|
|
63
|
+
...reasoningOptions.modelKwargs || {}
|
|
61
64
|
},
|
|
62
65
|
configuration: {
|
|
63
66
|
baseURL: this.getResolvedBaseURL()
|
|
@@ -130,6 +133,19 @@ class OpenAIResponsesProvider extends import_provider.LLMProvider {
|
|
|
130
133
|
}
|
|
131
134
|
return [];
|
|
132
135
|
}
|
|
136
|
+
resolveReasoningOptions(reasoning) {
|
|
137
|
+
if (!reasoning || reasoning.mode === "default") {
|
|
138
|
+
return {};
|
|
139
|
+
}
|
|
140
|
+
const effort = reasoning.mode === "off" ? "none" : reasoning.mode;
|
|
141
|
+
return {
|
|
142
|
+
modelRequestParams: {
|
|
143
|
+
reasoning: {
|
|
144
|
+
effort
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
133
149
|
isToolConflict() {
|
|
134
150
|
return false;
|
|
135
151
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { LLMProvider } from './provider';
|
|
10
|
+
import { LLMProviderMeta } from '../manager/ai-manager';
|
|
11
|
+
import { AIMessageChunk, BaseMessageChunk } from '@langchain/core/messages';
|
|
12
|
+
import { ReasoningChatOpenAI } from './common/reasoning';
|
|
13
|
+
import { AttachmentModel } from '@nocobase/plugin-file-manager';
|
|
14
|
+
import { Model } from '@nocobase/database';
|
|
15
|
+
export declare class OrcaRouterProvider extends LLMProvider {
|
|
16
|
+
chatModel: ReasoningChatOpenAI;
|
|
17
|
+
get baseURL(): string;
|
|
18
|
+
createModel(): ChatOrcaRouterCompletions;
|
|
19
|
+
protected isApiSupportedAttachment(attachment: AttachmentModel): boolean;
|
|
20
|
+
parseResponseMessage(message: Model): {
|
|
21
|
+
key: any;
|
|
22
|
+
createdAt: any;
|
|
23
|
+
content: any;
|
|
24
|
+
role: any;
|
|
25
|
+
};
|
|
26
|
+
parseReasoningContent(chunk: AIMessageChunk): {
|
|
27
|
+
status: string;
|
|
28
|
+
content: string;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
declare class ChatOrcaRouterCompletions extends ReasoningChatOpenAI {
|
|
32
|
+
_convertCompletionsDeltaToBaseMessageChunk(delta: any, rawResponse: any, defaultRole: any): BaseMessageChunk;
|
|
33
|
+
}
|
|
34
|
+
export declare const orcarouterProviderOptions: LLMProviderMeta;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
+
var orcarouter_exports = {};
|
|
38
|
+
__export(orcarouter_exports, {
|
|
39
|
+
OrcaRouterProvider: () => OrcaRouterProvider,
|
|
40
|
+
orcarouterProviderOptions: () => orcarouterProviderOptions
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(orcarouter_exports);
|
|
43
|
+
var import_provider = require("./provider");
|
|
44
|
+
var import_ai_manager = require("../manager/ai-manager");
|
|
45
|
+
var import_lodash = __toESM(require("lodash"));
|
|
46
|
+
var import_openai = require("@langchain/openai");
|
|
47
|
+
var import_messages = require("@langchain/core/messages");
|
|
48
|
+
var import_reasoning = require("./common/reasoning");
|
|
49
|
+
class OrcaRouterProvider extends import_provider.LLMProvider {
|
|
50
|
+
get baseURL() {
|
|
51
|
+
return "https://api.orcarouter.ai/v1";
|
|
52
|
+
}
|
|
53
|
+
createModel() {
|
|
54
|
+
const { apiKey, httpReferer, xTitle } = this.serviceOptions || {};
|
|
55
|
+
const { responseFormat, structuredOutput } = this.modelOptions || {};
|
|
56
|
+
const { name, schema } = structuredOutput || {};
|
|
57
|
+
const responseFormatOptions = {
|
|
58
|
+
type: responseFormat ?? "text"
|
|
59
|
+
};
|
|
60
|
+
if (responseFormat === "json_schema" && schema) {
|
|
61
|
+
responseFormatOptions["json_schema"] = { schema, name: name ?? "schema" };
|
|
62
|
+
}
|
|
63
|
+
const defaultHeaders = {};
|
|
64
|
+
if (httpReferer) {
|
|
65
|
+
defaultHeaders["HTTP-Referer"] = httpReferer;
|
|
66
|
+
}
|
|
67
|
+
if (xTitle) {
|
|
68
|
+
defaultHeaders["X-Title"] = xTitle;
|
|
69
|
+
}
|
|
70
|
+
return new ChatOrcaRouterCompletions({
|
|
71
|
+
apiKey,
|
|
72
|
+
...this.modelOptions,
|
|
73
|
+
modelKwargs: {
|
|
74
|
+
response_format: responseFormatOptions
|
|
75
|
+
},
|
|
76
|
+
configuration: {
|
|
77
|
+
baseURL: this.getResolvedBaseURL(),
|
|
78
|
+
...Object.keys(defaultHeaders).length ? { defaultHeaders } : {}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
isApiSupportedAttachment(attachment) {
|
|
83
|
+
const media = ["image/"];
|
|
84
|
+
return media.some((it) => {
|
|
85
|
+
var _a;
|
|
86
|
+
return (_a = attachment == null ? void 0 : attachment.mimetype) == null ? void 0 : _a.startsWith(it);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
parseResponseMessage(message) {
|
|
90
|
+
var _a;
|
|
91
|
+
const result = super.parseResponseMessage(message);
|
|
92
|
+
if (["user", "tool"].includes(result == null ? void 0 : result.role)) {
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
const { metadata } = (message == null ? void 0 : message.toJSON()) ?? {};
|
|
96
|
+
if (!import_lodash.default.isEmpty((_a = metadata == null ? void 0 : metadata.additional_kwargs) == null ? void 0 : _a.reasoning_content)) {
|
|
97
|
+
result.content = {
|
|
98
|
+
...result.content ?? {},
|
|
99
|
+
reasoning: {
|
|
100
|
+
status: "stop",
|
|
101
|
+
content: metadata == null ? void 0 : metadata.additional_kwargs.reasoning_content
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
parseReasoningContent(chunk) {
|
|
108
|
+
var _a;
|
|
109
|
+
if (!import_lodash.default.isEmpty((_a = chunk == null ? void 0 : chunk.additional_kwargs) == null ? void 0 : _a.reasoning_content)) {
|
|
110
|
+
return {
|
|
111
|
+
status: "streaming",
|
|
112
|
+
content: chunk.additional_kwargs.reasoning_content
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
class ChatOrcaRouterCompletions extends import_reasoning.ReasoningChatOpenAI {
|
|
119
|
+
_convertCompletionsDeltaToBaseMessageChunk(delta, rawResponse, defaultRole) {
|
|
120
|
+
const chunk = (0, import_openai.convertCompletionsDeltaToBaseMessageChunk)({
|
|
121
|
+
delta,
|
|
122
|
+
rawResponse,
|
|
123
|
+
includeRawResponse: this.__includeRawResponse,
|
|
124
|
+
defaultRole
|
|
125
|
+
});
|
|
126
|
+
if (chunk instanceof import_messages.AIMessageChunk) {
|
|
127
|
+
if (delta.reasoning_content) {
|
|
128
|
+
chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return chunk;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const orcarouterProviderOptions = {
|
|
135
|
+
title: "OrcaRouter",
|
|
136
|
+
supportedModel: [import_ai_manager.SupportedModel.LLM],
|
|
137
|
+
models: {
|
|
138
|
+
[import_ai_manager.SupportedModel.LLM]: [
|
|
139
|
+
"orcarouter/auto",
|
|
140
|
+
"openai/gpt-5.5",
|
|
141
|
+
"google/gemini-3.5-flash",
|
|
142
|
+
"anthropic/claude-opus-4.8",
|
|
143
|
+
"grok/grok-4.3",
|
|
144
|
+
"deepseek/deepseek-v4-pro",
|
|
145
|
+
"minimax/minimax-m2.7",
|
|
146
|
+
"qwen/qwen3.7-max"
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
provider: OrcaRouterProvider
|
|
150
|
+
};
|
|
151
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
152
|
+
0 && (module.exports = {
|
|
153
|
+
OrcaRouterProvider,
|
|
154
|
+
orcarouterProviderOptions
|
|
155
|
+
});
|
|
@@ -27,6 +27,11 @@ export type LLMProviderInvokeOptions = {
|
|
|
27
27
|
modelRequestParams?: Record<string, any>;
|
|
28
28
|
[key: string]: any;
|
|
29
29
|
};
|
|
30
|
+
export type ReasoningMode = 'default' | 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
|
31
|
+
export type ReasoningOptions = {
|
|
32
|
+
mode: ReasoningMode;
|
|
33
|
+
};
|
|
34
|
+
export type ResolvedReasoningOptions = Pick<LLMProviderInvokeOptions, 'modelKwargs' | 'modelRequestParams'>;
|
|
30
35
|
export type LLMModelRequestBuilderResult = {
|
|
31
36
|
context: AIChatContext;
|
|
32
37
|
options?: LLMProviderInvokeOptions;
|
|
@@ -45,10 +50,12 @@ export declare abstract class LLMProvider {
|
|
|
45
50
|
serviceOptions: Record<string, any>;
|
|
46
51
|
modelOptions: Record<string, any> | undefined;
|
|
47
52
|
chatModel: any;
|
|
53
|
+
protected modelReasoningOptions: ReasoningOptions | undefined;
|
|
48
54
|
abstract createModel(): BaseChatModel | any;
|
|
49
55
|
get baseURL(): string | null;
|
|
50
56
|
constructor(opts: LLMProviderOptions);
|
|
51
57
|
protected getModelRequestBuilder(_model?: string): LLMModelRequestBuilder | null;
|
|
58
|
+
protected resolveReasoningOptions(_reasoning?: ReasoningOptions): ResolvedReasoningOptions;
|
|
52
59
|
prepareChain(context: AIChatContext): any;
|
|
53
60
|
invoke(context: AIChatContext, options?: LLMProviderInvokeOptions): Promise<any>;
|
|
54
61
|
stream(context: AIChatContext, options?: any): Promise<any>;
|
|
@@ -84,6 +84,7 @@ class LLMProvider {
|
|
|
84
84
|
serviceOptions;
|
|
85
85
|
modelOptions;
|
|
86
86
|
chatModel;
|
|
87
|
+
modelReasoningOptions;
|
|
87
88
|
get baseURL() {
|
|
88
89
|
return null;
|
|
89
90
|
}
|
|
@@ -92,13 +93,18 @@ class LLMProvider {
|
|
|
92
93
|
this.app = app;
|
|
93
94
|
this.serviceOptions = resolveServiceOptions(serviceOptions, app);
|
|
94
95
|
if (modelOptions) {
|
|
95
|
-
|
|
96
|
+
const { _reasoning, ...restModelOptions } = modelOptions;
|
|
97
|
+
this.modelReasoningOptions = _reasoning;
|
|
98
|
+
this.modelOptions = restModelOptions;
|
|
96
99
|
this.chatModel = this.createModel();
|
|
97
100
|
}
|
|
98
101
|
}
|
|
99
102
|
getModelRequestBuilder(_model) {
|
|
100
103
|
return null;
|
|
101
104
|
}
|
|
105
|
+
resolveReasoningOptions(_reasoning) {
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
102
108
|
prepareChain(context) {
|
|
103
109
|
var _a, _b, _c, _d;
|
|
104
110
|
let chain = this.chatModel;
|