plugin-custom-llm 1.2.2 → 1.3.0
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/README.md +104 -104
- package/dist/client/index.js +1 -1
- package/dist/externalVersion.js +2 -2
- package/dist/locale/en-US.json +31 -29
- package/dist/locale/vi-VN.json +31 -29
- package/dist/locale/zh-CN.json +16 -16
- package/dist/server/llm-providers/custom-llm.js +158 -30
- package/package.json +36 -36
- package/src/client/client.d.ts +9 -0
- package/src/client/index.tsx +28 -19
- package/src/client/llm-providers/custom-llm/ModelSettings.tsx +148 -139
- package/src/client/llm-providers/custom-llm/ProviderSettings.tsx +133 -115
- package/src/client/llm-providers/custom-llm/index.ts +19 -10
- package/src/client/locale.ts +17 -8
- package/src/client/plugin.tsx +9 -0
- package/src/index.ts +9 -0
- package/src/locale/en-US.json +31 -29
- package/src/locale/vi-VN.json +31 -29
- package/src/locale/zh-CN.json +16 -16
- package/src/server/index.ts +9 -0
- package/src/server/llm-providers/custom-llm.ts +1183 -992
- package/src/server/plugin.ts +36 -27
- package/src/swagger.ts +18 -9
|
@@ -58,6 +58,90 @@ function getChatOpenAI() {
|
|
|
58
58
|
}
|
|
59
59
|
return _ChatOpenAI;
|
|
60
60
|
}
|
|
61
|
+
let _ChatOpenAICompletions = null;
|
|
62
|
+
function getChatOpenAICompletions() {
|
|
63
|
+
if (!_ChatOpenAICompletions) {
|
|
64
|
+
const mod = requireFromApp("@langchain/openai");
|
|
65
|
+
_ChatOpenAICompletions = mod.ChatOpenAICompletions;
|
|
66
|
+
}
|
|
67
|
+
return _ChatOpenAICompletions;
|
|
68
|
+
}
|
|
69
|
+
function getToolCallsKey(toolCalls = []) {
|
|
70
|
+
return toolCalls.map((tc) => {
|
|
71
|
+
var _a;
|
|
72
|
+
const id = (tc == null ? void 0 : tc.id) ?? "";
|
|
73
|
+
const name = (tc == null ? void 0 : tc.name) ?? ((_a = tc == null ? void 0 : tc.function) == null ? void 0 : _a.name) ?? "";
|
|
74
|
+
return `${id}:${name}`;
|
|
75
|
+
}).join("|");
|
|
76
|
+
}
|
|
77
|
+
function collectReasoningMap(messages) {
|
|
78
|
+
var _a, _b, _c, _d;
|
|
79
|
+
const reasoningMap = /* @__PURE__ */ new Map();
|
|
80
|
+
for (const message of messages ?? []) {
|
|
81
|
+
if (((_a = message == null ? void 0 : message.getType) == null ? void 0 : _a.call(message)) !== "ai" && ((_b = message == null ? void 0 : message._getType) == null ? void 0 : _b.call(message)) !== "ai") continue;
|
|
82
|
+
if (!((_c = message == null ? void 0 : message.tool_calls) == null ? void 0 : _c.length)) continue;
|
|
83
|
+
const reasoningContent = (_d = message == null ? void 0 : message.additional_kwargs) == null ? void 0 : _d.reasoning_content;
|
|
84
|
+
if (typeof reasoningContent !== "string" || !reasoningContent) continue;
|
|
85
|
+
const key = getToolCallsKey(message.tool_calls);
|
|
86
|
+
if (key) reasoningMap.set(key, reasoningContent);
|
|
87
|
+
}
|
|
88
|
+
return reasoningMap;
|
|
89
|
+
}
|
|
90
|
+
function patchRequestMessagesReasoning(request, reasoningMap) {
|
|
91
|
+
if (!(reasoningMap == null ? void 0 : reasoningMap.size) || !Array.isArray(request == null ? void 0 : request.messages)) return;
|
|
92
|
+
const lastMsg = request.messages.at(-1);
|
|
93
|
+
if ((lastMsg == null ? void 0 : lastMsg.role) !== "tool") return;
|
|
94
|
+
for (const msg of request.messages) {
|
|
95
|
+
if ((msg == null ? void 0 : msg.role) !== "assistant") continue;
|
|
96
|
+
if (!Array.isArray(msg.tool_calls) || msg.tool_calls.length === 0) continue;
|
|
97
|
+
if (msg.reasoning_content) continue;
|
|
98
|
+
const key = getToolCallsKey(msg.tool_calls);
|
|
99
|
+
const rc = key ? reasoningMap.get(key) : void 0;
|
|
100
|
+
if (rc) msg.reasoning_content = rc;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const REASONING_MAP_KEY = "__nb_reasoning_map";
|
|
104
|
+
function createReasoningChatClass() {
|
|
105
|
+
const ChatOpenAICompletions = getChatOpenAICompletions();
|
|
106
|
+
if (!ChatOpenAICompletions) {
|
|
107
|
+
return getChatOpenAI();
|
|
108
|
+
}
|
|
109
|
+
return class ReasoningChatOpenAI extends ChatOpenAICompletions {
|
|
110
|
+
async _generate(messages, options, runManager) {
|
|
111
|
+
const reasoningMap = collectReasoningMap(messages);
|
|
112
|
+
return super._generate(messages, { ...options || {}, [REASONING_MAP_KEY]: reasoningMap }, runManager);
|
|
113
|
+
}
|
|
114
|
+
async *_streamResponseChunks(messages, options, runManager) {
|
|
115
|
+
const reasoningMap = (options == null ? void 0 : options[REASONING_MAP_KEY]) instanceof Map ? options[REASONING_MAP_KEY] : collectReasoningMap(messages);
|
|
116
|
+
yield* super._streamResponseChunks(messages, { ...options || {}, [REASONING_MAP_KEY]: reasoningMap }, runManager);
|
|
117
|
+
}
|
|
118
|
+
_convertCompletionsDeltaToBaseMessageChunk(delta, rawResponse, defaultRole) {
|
|
119
|
+
const messageChunk = super._convertCompletionsDeltaToBaseMessageChunk(delta, rawResponse, defaultRole);
|
|
120
|
+
if (delta == null ? void 0 : delta.reasoning_content) {
|
|
121
|
+
messageChunk.additional_kwargs = {
|
|
122
|
+
...messageChunk.additional_kwargs || {},
|
|
123
|
+
reasoning_content: delta.reasoning_content
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return messageChunk;
|
|
127
|
+
}
|
|
128
|
+
_convertCompletionsMessageToBaseMessage(message, rawResponse) {
|
|
129
|
+
const langChainMessage = super._convertCompletionsMessageToBaseMessage(message, rawResponse);
|
|
130
|
+
if (message == null ? void 0 : message.reasoning_content) {
|
|
131
|
+
langChainMessage.additional_kwargs = {
|
|
132
|
+
...langChainMessage.additional_kwargs || {},
|
|
133
|
+
reasoning_content: message.reasoning_content
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return langChainMessage;
|
|
137
|
+
}
|
|
138
|
+
async completionWithRetry(request, requestOptions) {
|
|
139
|
+
const reasoningMap = requestOptions == null ? void 0 : requestOptions[REASONING_MAP_KEY];
|
|
140
|
+
patchRequestMessagesReasoning(request, reasoningMap);
|
|
141
|
+
return super.completionWithRetry(request, requestOptions);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
61
145
|
let _ChatGenerationChunk = null;
|
|
62
146
|
function getChatGenerationChunk() {
|
|
63
147
|
if (!_ChatGenerationChunk) {
|
|
@@ -150,12 +234,25 @@ function getByPath(obj, dotPath) {
|
|
|
150
234
|
}
|
|
151
235
|
return current;
|
|
152
236
|
}
|
|
153
|
-
function createMappingFetch(responseMapping) {
|
|
237
|
+
function createMappingFetch(responseMapping, timeoutMs) {
|
|
154
238
|
const contentPath = responseMapping.content;
|
|
155
239
|
if (!contentPath) return void 0;
|
|
240
|
+
const toolCallsPath = responseMapping.tool_calls;
|
|
241
|
+
const finishReasonPath = responseMapping.finish_reason;
|
|
156
242
|
return async (url, init) => {
|
|
157
243
|
var _a, _b;
|
|
158
|
-
|
|
244
|
+
let response;
|
|
245
|
+
if (timeoutMs && timeoutMs > 0) {
|
|
246
|
+
const controller = new AbortController();
|
|
247
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
248
|
+
try {
|
|
249
|
+
response = await fetch(url, { ...init, signal: controller.signal });
|
|
250
|
+
} finally {
|
|
251
|
+
clearTimeout(timer);
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
response = await fetch(url, init);
|
|
255
|
+
}
|
|
159
256
|
if (!response.ok) return response;
|
|
160
257
|
const contentType = response.headers.get("content-type") || "";
|
|
161
258
|
if (contentType.includes("text/event-stream") || ((_a = init == null ? void 0 : init.headers) == null ? void 0 : _a["Accept"]) === "text/event-stream") {
|
|
@@ -186,17 +283,28 @@ function createMappingFetch(responseMapping) {
|
|
|
186
283
|
try {
|
|
187
284
|
const parsed = JSON.parse(data);
|
|
188
285
|
const mappedContent = getByPath(parsed, contentPath);
|
|
189
|
-
|
|
286
|
+
const mappedToolCalls = toolCallsPath ? getByPath(parsed, toolCallsPath) : getByPath(parsed, "choices.0.delta.tool_calls") ?? getByPath(parsed, "delta.tool_calls");
|
|
287
|
+
const mappedFinishReason = finishReasonPath ? getByPath(parsed, finishReasonPath) : getByPath(parsed, "choices.0.finish_reason") ?? getByPath(parsed, "finish_reason");
|
|
288
|
+
if (mappedContent !== void 0 || mappedToolCalls) {
|
|
289
|
+
const delta = { role: "assistant" };
|
|
290
|
+
if (mappedContent !== void 0) {
|
|
291
|
+
delta.content = String(mappedContent);
|
|
292
|
+
}
|
|
293
|
+
if (mappedToolCalls) {
|
|
294
|
+
delta.tool_calls = mappedToolCalls;
|
|
295
|
+
}
|
|
190
296
|
const mapped = {
|
|
191
297
|
id: getByPath(parsed, responseMapping.id || "id") || "chatcmpl-custom",
|
|
192
298
|
object: "chat.completion.chunk",
|
|
193
299
|
created: Math.floor(Date.now() / 1e3),
|
|
194
300
|
model: "custom",
|
|
195
|
-
choices: [
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
301
|
+
choices: [
|
|
302
|
+
{
|
|
303
|
+
index: 0,
|
|
304
|
+
delta,
|
|
305
|
+
finish_reason: mappedFinishReason ?? null
|
|
306
|
+
}
|
|
307
|
+
]
|
|
200
308
|
};
|
|
201
309
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify(mapped)}
|
|
202
310
|
|
|
@@ -228,21 +336,33 @@ function createMappingFetch(responseMapping) {
|
|
|
228
336
|
if (contentType.includes("application/json")) {
|
|
229
337
|
const body = await response.json();
|
|
230
338
|
const mappedContent = getByPath(body, contentPath);
|
|
231
|
-
|
|
339
|
+
const mappedToolCalls = toolCallsPath ? getByPath(body, toolCallsPath) : getByPath(body, "choices.0.message.tool_calls") ?? getByPath(body, "message.tool_calls");
|
|
340
|
+
const mappedFinishReason = finishReasonPath ? getByPath(body, finishReasonPath) : getByPath(body, "choices.0.finish_reason") ?? getByPath(body, "finish_reason");
|
|
341
|
+
if (mappedContent !== void 0 || mappedToolCalls) {
|
|
342
|
+
const message = {
|
|
343
|
+
role: getByPath(body, responseMapping.role || "") || "assistant"
|
|
344
|
+
};
|
|
345
|
+
if (mappedContent !== void 0) {
|
|
346
|
+
message.content = String(mappedContent);
|
|
347
|
+
} else {
|
|
348
|
+
message.content = null;
|
|
349
|
+
}
|
|
350
|
+
if (mappedToolCalls) {
|
|
351
|
+
message.tool_calls = mappedToolCalls;
|
|
352
|
+
}
|
|
232
353
|
const mapped = {
|
|
233
354
|
id: getByPath(body, responseMapping.id || "id") || "chatcmpl-custom",
|
|
234
355
|
object: "chat.completion",
|
|
235
356
|
created: Math.floor(Date.now() / 1e3),
|
|
236
357
|
model: "custom",
|
|
237
|
-
choices: [
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
|
|
358
|
+
choices: [
|
|
359
|
+
{
|
|
360
|
+
index: 0,
|
|
361
|
+
message,
|
|
362
|
+
finish_reason: mappedFinishReason ?? (mappedToolCalls ? "tool_calls" : "stop")
|
|
363
|
+
}
|
|
364
|
+
],
|
|
365
|
+
usage: body.usage ?? { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
|
|
246
366
|
};
|
|
247
367
|
return new Response(JSON.stringify(mapped), {
|
|
248
368
|
status: response.status,
|
|
@@ -431,7 +551,15 @@ class CustomLLMProvider extends import_plugin_ai.LLMProvider {
|
|
|
431
551
|
}
|
|
432
552
|
createModel() {
|
|
433
553
|
var _a;
|
|
434
|
-
const {
|
|
554
|
+
const {
|
|
555
|
+
apiKey,
|
|
556
|
+
disableStream,
|
|
557
|
+
timeout,
|
|
558
|
+
streamKeepAlive,
|
|
559
|
+
keepAliveIntervalMs,
|
|
560
|
+
keepAliveContent,
|
|
561
|
+
enableReasoning
|
|
562
|
+
} = this.serviceOptions || {};
|
|
435
563
|
const baseURL = (_a = this.serviceOptions) == null ? void 0 : _a.baseURL;
|
|
436
564
|
const { responseFormat } = this.modelOptions || {};
|
|
437
565
|
const reqConfig = this.requestConfig;
|
|
@@ -446,7 +574,7 @@ class CustomLLMProvider extends import_plugin_ai.LLMProvider {
|
|
|
446
574
|
if (reqConfig.extraBody && typeof reqConfig.extraBody === "object") {
|
|
447
575
|
Object.assign(modelKwargs, reqConfig.extraBody);
|
|
448
576
|
}
|
|
449
|
-
const
|
|
577
|
+
const ChatClass = enableReasoning ? createReasoningChatClass() : getChatOpenAI();
|
|
450
578
|
const config = {
|
|
451
579
|
apiKey,
|
|
452
580
|
...this.modelOptions,
|
|
@@ -459,17 +587,18 @@ class CustomLLMProvider extends import_plugin_ai.LLMProvider {
|
|
|
459
587
|
if (disableStream) {
|
|
460
588
|
config.streaming = false;
|
|
461
589
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
config.
|
|
590
|
+
const timeoutMs = timeout && Number(timeout) > 0 ? Number(timeout) : 0;
|
|
591
|
+
if (timeoutMs) {
|
|
592
|
+
config.timeout = timeoutMs;
|
|
593
|
+
config.configuration.timeout = timeoutMs;
|
|
465
594
|
}
|
|
466
595
|
if (reqConfig.extraHeaders && typeof reqConfig.extraHeaders === "object") {
|
|
467
596
|
config.configuration.defaultHeaders = reqConfig.extraHeaders;
|
|
468
597
|
}
|
|
469
598
|
if (resConfig.responseMapping) {
|
|
470
|
-
config.configuration.fetch = createMappingFetch(resConfig.responseMapping);
|
|
599
|
+
config.configuration.fetch = createMappingFetch(resConfig.responseMapping, timeoutMs || 12e4);
|
|
471
600
|
}
|
|
472
|
-
let model = new
|
|
601
|
+
let model = new ChatClass(config);
|
|
473
602
|
model = fixEmptyToolProperties(model);
|
|
474
603
|
if (streamKeepAlive && !disableStream) {
|
|
475
604
|
return wrapWithStreamKeepAlive(model, {
|
|
@@ -505,8 +634,7 @@ class CustomLLMProvider extends import_plugin_ai.LLMProvider {
|
|
|
505
634
|
content.content = textBlocks.map((block) => block.text).join("") || "";
|
|
506
635
|
}
|
|
507
636
|
if (typeof content.content === "string") {
|
|
508
|
-
|
|
509
|
-
content.content = content.content.replace(new RegExp(escapedPrefix + ".*?(?=" + escapedPrefix + "|$)", "g"), "");
|
|
637
|
+
content.content = content.content.replaceAll(KEEPALIVE_PREFIX, "");
|
|
510
638
|
content.content = stripToolCallTags(content.content);
|
|
511
639
|
}
|
|
512
640
|
if (((_b = (_a = content.metadata) == null ? void 0 : _a.additional_kwargs) == null ? void 0 : _b.__keepalive) !== void 0) {
|
|
@@ -640,10 +768,10 @@ class CustomLLMProvider extends import_plugin_ai.LLMProvider {
|
|
|
640
768
|
* from DB. Result is cached on `ctx.state._docPixieActive` for the request lifetime.
|
|
641
769
|
*/
|
|
642
770
|
async hasDocPixieSkill(ctx) {
|
|
643
|
-
var _a, _b, _c, _d, _e;
|
|
771
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
644
772
|
if (ctx.state._docPixieActive !== void 0) return ctx.state._docPixieActive;
|
|
645
773
|
try {
|
|
646
|
-
const employeeUsername = (_c = (_b = (_a = ctx.action) == null ? void 0 : _a.params) == null ? void 0 : _b.values) == null ? void 0 : _c.aiEmployee;
|
|
774
|
+
const employeeUsername = ((_c = (_b = (_a = ctx.action) == null ? void 0 : _a.params) == null ? void 0 : _b.values) == null ? void 0 : _c.aiEmployee) ?? ((_e = (_d = ctx.action) == null ? void 0 : _d.params) == null ? void 0 : _e.aiEmployee) ?? ((_f = ctx.state) == null ? void 0 : _f.currentAiEmployee);
|
|
647
775
|
if (!employeeUsername) {
|
|
648
776
|
ctx.state._docPixieActive = false;
|
|
649
777
|
return false;
|
|
@@ -652,7 +780,7 @@ class CustomLLMProvider extends import_plugin_ai.LLMProvider {
|
|
|
652
780
|
filter: { username: String(employeeUsername) },
|
|
653
781
|
fields: ["skillSettings"]
|
|
654
782
|
});
|
|
655
|
-
const skills = ((
|
|
783
|
+
const skills = ((_h = (_g = employee == null ? void 0 : employee.get) == null ? void 0 : _g.call(employee, "skillSettings")) == null ? void 0 : _h.skills) ?? [];
|
|
656
784
|
const has = skills.some((s) => s.name === "docpixie.query.document");
|
|
657
785
|
ctx.state._docPixieActive = has;
|
|
658
786
|
return has;
|
package/package.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "plugin-custom-llm",
|
|
3
|
-
"displayName": "AI LLM: Custom (OpenAI Compatible)",
|
|
4
|
-
"displayName.zh-CN": "AI LLM:自定义(OpenAI 兼容)",
|
|
5
|
-
"description": "OpenAI-compatible LLM provider with auto response format detection for external LLM services.",
|
|
6
|
-
"version": "1.
|
|
7
|
-
"main": "dist/server/index.js",
|
|
8
|
-
"files": [
|
|
9
|
-
"dist",
|
|
10
|
-
"client.js",
|
|
11
|
-
"client.d.ts",
|
|
12
|
-
"server.js",
|
|
13
|
-
"server.d.ts",
|
|
14
|
-
"src"
|
|
15
|
-
],
|
|
16
|
-
"nocobase": {
|
|
17
|
-
"supportedVersions": [
|
|
18
|
-
"2.x"
|
|
19
|
-
],
|
|
20
|
-
"editionLevel": 0
|
|
21
|
-
},
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"@langchain/openai": "^1.0.0",
|
|
24
|
-
"@langchain/core": "^1.0.0"
|
|
25
|
-
},
|
|
26
|
-
"peerDependencies": {
|
|
27
|
-
"@nocobase/client": "2.x",
|
|
28
|
-
"@nocobase/plugin-ai": "2.x",
|
|
29
|
-
"@nocobase/server": "2.x",
|
|
30
|
-
"@nocobase/test": "2.x"
|
|
31
|
-
},
|
|
32
|
-
"keywords": [
|
|
33
|
-
"AI"
|
|
34
|
-
],
|
|
35
|
-
"license": "Apache-2.0"
|
|
36
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "plugin-custom-llm",
|
|
3
|
+
"displayName": "AI LLM: Custom (OpenAI Compatible)",
|
|
4
|
+
"displayName.zh-CN": "AI LLM:自定义(OpenAI 兼容)",
|
|
5
|
+
"description": "OpenAI-compatible LLM provider with auto response format detection for external LLM services.",
|
|
6
|
+
"version": "1.3.0",
|
|
7
|
+
"main": "dist/server/index.js",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"client.js",
|
|
11
|
+
"client.d.ts",
|
|
12
|
+
"server.js",
|
|
13
|
+
"server.d.ts",
|
|
14
|
+
"src"
|
|
15
|
+
],
|
|
16
|
+
"nocobase": {
|
|
17
|
+
"supportedVersions": [
|
|
18
|
+
"2.x"
|
|
19
|
+
],
|
|
20
|
+
"editionLevel": 0
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@langchain/openai": "^1.0.0",
|
|
24
|
+
"@langchain/core": "^1.0.0"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@nocobase/client": "2.x",
|
|
28
|
+
"@nocobase/plugin-ai": "2.x",
|
|
29
|
+
"@nocobase/server": "2.x",
|
|
30
|
+
"@nocobase/test": "2.x"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"AI"
|
|
34
|
+
],
|
|
35
|
+
"license": "Apache-2.0"
|
|
36
|
+
}
|
package/src/client/client.d.ts
CHANGED
|
@@ -7,6 +7,15 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* This file is part of the NocoBase (R) project.
|
|
12
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
13
|
+
* Authors: NocoBase Team.
|
|
14
|
+
*
|
|
15
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
16
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
17
|
+
*/
|
|
18
|
+
|
|
10
19
|
// CSS modules
|
|
11
20
|
type CSSModuleClasses = { readonly [key: string]: string };
|
|
12
21
|
|
package/src/client/index.tsx
CHANGED
|
@@ -1,19 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
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
|
+
import { Plugin } from '@nocobase/client';
|
|
11
|
+
import PluginAIClient from '@nocobase/plugin-ai/client';
|
|
12
|
+
import { customLLMProviderOptions } from './llm-providers/custom-llm';
|
|
13
|
+
|
|
14
|
+
export class PluginCustomLLMClient extends Plugin {
|
|
15
|
+
async afterAdd() {}
|
|
16
|
+
|
|
17
|
+
async beforeLoad() {}
|
|
18
|
+
|
|
19
|
+
async load() {
|
|
20
|
+
this.aiPlugin.aiManager.registerLLMProvider('custom-llm', customLLMProviderOptions);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private get aiPlugin(): PluginAIClient {
|
|
24
|
+
return this.app.pm.get('ai');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default PluginCustomLLMClient;
|