koishi-plugin-chatluna-google-gemini-adapter 1.2.6 → 1.2.8
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/lib/index.cjs +61 -67
- package/lib/index.mjs +61 -67
- package/lib/utils.d.ts +1 -0
- package/package.json +2 -2
package/lib/index.cjs
CHANGED
|
@@ -33,14 +33,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
33
33
|
// src/locales/zh-CN.schema.yml
|
|
34
34
|
var require_zh_CN_schema = __commonJS({
|
|
35
35
|
"src/locales/zh-CN.schema.yml"(exports2, module2) {
|
|
36
|
-
module2.exports = { $inner: [{}, { $desc: "请求选项", platform: "适配器的平台名。(不懂请不要修改)", apiKeys: { $inner: ["Gemini 的 API Key", "Gemini API 的请求地址"], $desc: "Gemini 的 API Key 和请求地址列表。" } }, { $desc: "模型配置", maxTokens: "输入的最大上下文 Token(16~2097000,必须是 16 的倍数)。注意:仅当您使用的模型最大 Token 为 8000 及以上时,才建议设置超过 2000 token。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。", googleSearch: "为模型启用谷歌搜索。", thinkingBudget: "思考预算,范围:(-1~24576),设置的数值越大,思考时花费的 Token 越多,-1
|
|
36
|
+
module2.exports = { $inner: [{}, { $desc: "请求选项", platform: "适配器的平台名。(不懂请不要修改)", apiKeys: { $inner: ["Gemini 的 API Key", "Gemini API 的请求地址"], $desc: "Gemini 的 API Key 和请求地址列表。" } }, { $desc: "模型配置", maxTokens: "输入的最大上下文 Token(16~2097000,必须是 16 的倍数)。注意:仅当您使用的模型最大 Token 为 8000 及以上时,才建议设置超过 2000 token。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。", googleSearch: "为模型启用谷歌搜索。", thinkingBudget: "思考预算,范围:(-1~24576),设置的数值越大,思考时花费的 Token 越多,-1 为动态思考。目前仅支持 gemini 2.5 系列模型。", groundingContentDisplay: "是否显示谷歌搜索结果。", imageGeneration: "为模型启用图像生成。目前仅支持 `gemini-2.0-flash-exp` 模型。", searchThreshold: "搜索的[置信度阈值](https://ai.google.dev/gemini-api/docs/grounding?lang=rest#dynamic-retrieval),范围:0~1,设置的数值越低,则越倾向于使用谷歌搜索。(仅支持 `gemini-1.5` 系列模型。gemini 2.0 模型起使用动态的工具调用)", includeThoughts: "是否获取模型的思考内容。", codeExecution: "为模型启用代码执行工具。", urlContext: "为模型启用 URL 内容获取工具。" }] };
|
|
37
37
|
}
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
// src/locales/en-US.schema.yml
|
|
41
41
|
var require_en_US_schema = __commonJS({
|
|
42
42
|
"src/locales/en-US.schema.yml"(exports2, module2) {
|
|
43
|
-
module2.exports = { $inner: [{}, { $desc: "API Configuration", platform: "Adapter platform name. (Do not modify if you do not understand)", apiKeys: { $inner: ["Gemini API Key", "Gemini API Endpoint (optional)"], $desc: "Gemini API access credentials" } }, { $desc: "Model Parameters", maxTokens: "Max output tokens (16-2097000, multiple of 16). >2000 for 8k+ models", temperature: "Sampling temperature (0-2). Higher: more random, Lower: more deterministic", googleSearch: "Enable Google search", thinkingBudget: "Thinking budget (-1-24576). (
|
|
43
|
+
module2.exports = { $inner: [{}, { $desc: "API Configuration", platform: "Adapter platform name. (Do not modify if you do not understand)", apiKeys: { $inner: ["Gemini API Key", "Gemini API Endpoint (optional)"], $desc: "Gemini API access credentials" } }, { $desc: "Model Parameters", maxTokens: "Max output tokens (16-2097000, multiple of 16). >2000 for 8k+ models", temperature: "Sampling temperature (0-2). Higher: more random, Lower: more deterministic", googleSearch: "Enable Google search", thinkingBudget: "Thinking budget (-1-24576). (0: dynamic thinking) Higher: more tokens spent on thinking. Currently only supports `gemini-2.5` series models.", groundingContentDisplay: "Enable display of search results", imageGeneration: "Enable image generation (only for `gemini-2.0-flash-exp` model)", searchThreshold: "Search confidence [threshold](https://ai.google.dev/gemini-api/docs/grounding?lang=rest#dynamic-retrieval) (0-1). Lower: more likely to use Google search", includeThoughts: "Enable retrieval of model thoughts", codeExecution: "Enable code execution tool", urlContext: "Enable URL context retrieval tool" }] };
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
46
|
|
|
@@ -76,7 +76,7 @@ var import_stream = require("koishi-plugin-chatluna/utils/stream");
|
|
|
76
76
|
var import_messages = require("@langchain/core/messages");
|
|
77
77
|
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
78
78
|
async function langchainMessageToGeminiMessage(messages, model) {
|
|
79
|
-
const
|
|
79
|
+
const mappedMessages = await Promise.all(
|
|
80
80
|
messages.map(async (rawMessage) => {
|
|
81
81
|
const role = messageTypeToGeminiRole(rawMessage.getType());
|
|
82
82
|
if (role === "function" || rawMessage.additional_kwargs?.function_call != null) {
|
|
@@ -90,15 +90,15 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
90
90
|
name: rawMessage.name,
|
|
91
91
|
content: (() => {
|
|
92
92
|
try {
|
|
93
|
-
const
|
|
93
|
+
const result2 = JSON.parse(
|
|
94
94
|
rawMessage.content
|
|
95
95
|
);
|
|
96
|
-
if (typeof
|
|
96
|
+
if (typeof result2 === "string") {
|
|
97
97
|
return {
|
|
98
|
-
response:
|
|
98
|
+
response: result2
|
|
99
99
|
};
|
|
100
100
|
} else {
|
|
101
|
-
return
|
|
101
|
+
return result2;
|
|
102
102
|
}
|
|
103
103
|
} catch (e) {
|
|
104
104
|
return {
|
|
@@ -112,15 +112,15 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
112
112
|
name: rawMessage.additional_kwargs.function_call.name,
|
|
113
113
|
args: (() => {
|
|
114
114
|
try {
|
|
115
|
-
const
|
|
115
|
+
const result2 = JSON.parse(
|
|
116
116
|
rawMessage.additional_kwargs.function_call.arguments
|
|
117
117
|
);
|
|
118
|
-
if (typeof
|
|
118
|
+
if (typeof result2 === "string") {
|
|
119
119
|
return {
|
|
120
|
-
input:
|
|
120
|
+
input: result2
|
|
121
121
|
};
|
|
122
122
|
} else {
|
|
123
|
-
return
|
|
123
|
+
return result2;
|
|
124
124
|
}
|
|
125
125
|
} catch (e) {
|
|
126
126
|
return {
|
|
@@ -134,7 +134,7 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
134
134
|
};
|
|
135
135
|
}
|
|
136
136
|
const images = rawMessage.additional_kwargs.images;
|
|
137
|
-
const
|
|
137
|
+
const result = {
|
|
138
138
|
role,
|
|
139
139
|
parts: [
|
|
140
140
|
{
|
|
@@ -146,7 +146,7 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
146
146
|
for (const image of images) {
|
|
147
147
|
const mineType = image.split(";")?.[0]?.split(":")?.[1];
|
|
148
148
|
const data = image.replace(/^data:image\/\w+;base64,/, "");
|
|
149
|
-
|
|
149
|
+
result.parts.push({
|
|
150
150
|
inline_data: {
|
|
151
151
|
// base64 image match type
|
|
152
152
|
data,
|
|
@@ -154,7 +154,7 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
154
154
|
}
|
|
155
155
|
});
|
|
156
156
|
}
|
|
157
|
-
|
|
157
|
+
result.parts = result.parts.filter((uncheckedPart) => {
|
|
158
158
|
const part = partAsTypeCheck(
|
|
159
159
|
uncheckedPart,
|
|
160
160
|
(part2) => part2["text"] != null
|
|
@@ -162,54 +162,39 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
162
162
|
return part == null || part.text.length > 0;
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
|
-
return
|
|
165
|
+
return result;
|
|
166
166
|
})
|
|
167
167
|
);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
parts: message.parts
|
|
178
|
-
});
|
|
179
|
-
const nextMessage = mappedMessage?.[i + 1];
|
|
180
|
-
if (nextMessage?.role === "model") {
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
if (nextMessage?.role === "user" || nextMessage?.role === "system") {
|
|
184
|
-
result.push({
|
|
185
|
-
role: "model",
|
|
186
|
-
parts: [{ text: "Okay, what do I need to do?" }]
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
if (nextMessage?.role === "system") {
|
|
190
|
-
result.push({
|
|
191
|
-
role: "user",
|
|
192
|
-
parts: [
|
|
193
|
-
{
|
|
194
|
-
text: "Continue what I said to you last message. Follow these instructions."
|
|
195
|
-
}
|
|
196
|
-
]
|
|
197
|
-
});
|
|
168
|
+
return mappedMessages;
|
|
169
|
+
}
|
|
170
|
+
__name(langchainMessageToGeminiMessage, "langchainMessageToGeminiMessage");
|
|
171
|
+
function extractSystemMessages(messages) {
|
|
172
|
+
let lastSystemMessage;
|
|
173
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
174
|
+
if (messages[i].role === "system") {
|
|
175
|
+
lastSystemMessage = messages[i];
|
|
176
|
+
break;
|
|
198
177
|
}
|
|
199
178
|
}
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
role: "user",
|
|
203
|
-
parts: [
|
|
204
|
-
{
|
|
205
|
-
text: "Continue what I said to you last message. Follow these instructions."
|
|
206
|
-
}
|
|
207
|
-
]
|
|
208
|
-
});
|
|
179
|
+
if (lastSystemMessage == null) {
|
|
180
|
+
return [void 0, messages];
|
|
209
181
|
}
|
|
210
|
-
|
|
182
|
+
const systemMessages = messages.slice(
|
|
183
|
+
0,
|
|
184
|
+
messages.indexOf(lastSystemMessage)
|
|
185
|
+
);
|
|
186
|
+
return [
|
|
187
|
+
{
|
|
188
|
+
role: "user",
|
|
189
|
+
parts: systemMessages.reduce((acc, cur) => {
|
|
190
|
+
acc.push(...cur.parts);
|
|
191
|
+
return acc;
|
|
192
|
+
}, [])
|
|
193
|
+
},
|
|
194
|
+
messages.slice(messages.indexOf(lastSystemMessage))
|
|
195
|
+
];
|
|
211
196
|
}
|
|
212
|
-
__name(
|
|
197
|
+
__name(extractSystemMessages, "extractSystemMessages");
|
|
213
198
|
function partAsType(part) {
|
|
214
199
|
return part;
|
|
215
200
|
}
|
|
@@ -355,16 +340,24 @@ var GeminiRequester = class extends import_api.ModelRequester {
|
|
|
355
340
|
let model = params.model;
|
|
356
341
|
let enabledThinking = null;
|
|
357
342
|
if (model.includes("-thinking") && model.includes("gemini-2.5")) {
|
|
358
|
-
enabledThinking = !model.includes("-
|
|
359
|
-
model = model.replace("-
|
|
343
|
+
enabledThinking = !model.includes("-non-thinking");
|
|
344
|
+
model = model.replace("-nom-thinking", "").replace("-thinking", "");
|
|
345
|
+
}
|
|
346
|
+
const geminiMessages = await langchainMessageToGeminiMessage(
|
|
347
|
+
params.input,
|
|
348
|
+
model
|
|
349
|
+
);
|
|
350
|
+
const [systemInstruction, modelMessages] = extractSystemMessages(geminiMessages);
|
|
351
|
+
let thinkingBudget = this._pluginConfig.thinkingBudget ?? -1;
|
|
352
|
+
if (!enabledThinking && !model.includes("2.5-pro")) {
|
|
353
|
+
thinkingBudget = 0;
|
|
354
|
+
} else if (thinkingBudget >= 0 && thinkingBudget < 128) {
|
|
355
|
+
thinkingBudget = 128;
|
|
360
356
|
}
|
|
361
357
|
const response = await this._post(
|
|
362
358
|
`models/${model}:streamGenerateContent?alt=sse`,
|
|
363
359
|
{
|
|
364
|
-
contents:
|
|
365
|
-
params.input,
|
|
366
|
-
model
|
|
367
|
-
),
|
|
360
|
+
contents: modelMessages,
|
|
368
361
|
safetySettings: [
|
|
369
362
|
{
|
|
370
363
|
category: "HARM_CATEGORY_HARASSMENT",
|
|
@@ -397,10 +390,11 @@ var GeminiRequester = class extends import_api.ModelRequester {
|
|
|
397
390
|
"gemini-2.0-flash-exp"
|
|
398
391
|
) && this._pluginConfig.imageGeneration ? ["TEXT", "IMAGE"] : void 0,
|
|
399
392
|
thinkingConfig: enabledThinking != null || this._pluginConfig.includeThoughts ? {
|
|
400
|
-
thinkingBudget
|
|
393
|
+
thinkingBudget,
|
|
401
394
|
includeThoughts: this._pluginConfig.includeThoughts
|
|
402
395
|
} : void 0
|
|
403
396
|
},
|
|
397
|
+
systemInstruction: systemInstruction != null ? systemInstruction : void 0,
|
|
404
398
|
tools: params.tools != null || this._pluginConfig.googleSearch || this._pluginConfig.codeExecution || this._pluginConfig.urlContext ? formatToolsToGeminiAITools(
|
|
405
399
|
params.tools ?? [],
|
|
406
400
|
this._pluginConfig,
|
|
@@ -413,7 +407,7 @@ var GeminiRequester = class extends import_api.ModelRequester {
|
|
|
413
407
|
);
|
|
414
408
|
let errorCount = 0;
|
|
415
409
|
let groundingContent = "";
|
|
416
|
-
let
|
|
410
|
+
let currentGroundingIndex = 0;
|
|
417
411
|
await (0, import_sse.checkResponse)(response);
|
|
418
412
|
const readableStream = new ReadableStream({
|
|
419
413
|
async start(controller) {
|
|
@@ -444,7 +438,7 @@ var GeminiRequester = class extends import_api.ModelRequester {
|
|
|
444
438
|
controller.enqueue(part);
|
|
445
439
|
}
|
|
446
440
|
for (const source of candidate.groundingMetadata?.groundingChunks ?? []) {
|
|
447
|
-
groundingContent += `[^${
|
|
441
|
+
groundingContent += `[^${currentGroundingIndex++}]: [${source.web.title}](${source.web.uri})
|
|
448
442
|
`;
|
|
449
443
|
}
|
|
450
444
|
}
|
|
@@ -714,7 +708,7 @@ var GeminiClient = class extends import_client.PlatformModelAndEmbeddingsClient
|
|
|
714
708
|
if (model.name.includes("gemini-2.5") && !model.name.includes("pro")) {
|
|
715
709
|
if (!model.name.includes("-thinking")) {
|
|
716
710
|
models.push(
|
|
717
|
-
{ ...info, name: model.name + "-
|
|
711
|
+
{ ...info, name: model.name + "-nonthinking" },
|
|
718
712
|
{ ...info, name: model.name + "-thinking" },
|
|
719
713
|
info
|
|
720
714
|
);
|
|
@@ -814,7 +808,7 @@ var Config3 = import_koishi.Schema.intersect([
|
|
|
814
808
|
googleSearch: import_koishi.Schema.boolean().default(false),
|
|
815
809
|
codeExecution: import_koishi.Schema.boolean().default(false),
|
|
816
810
|
urlContext: import_koishi.Schema.boolean().default(false),
|
|
817
|
-
thinkingBudget: import_koishi.Schema.number().min(
|
|
811
|
+
thinkingBudget: import_koishi.Schema.number().min(-1).max(24576).default(-1),
|
|
818
812
|
includeThoughts: import_koishi.Schema.boolean().default(false),
|
|
819
813
|
imageGeneration: import_koishi.Schema.boolean().default(false),
|
|
820
814
|
groundingContentDisplay: import_koishi.Schema.boolean().default(false),
|
package/lib/index.mjs
CHANGED
|
@@ -8,14 +8,14 @@ var __commonJS = (cb, mod) => function __require() {
|
|
|
8
8
|
// src/locales/zh-CN.schema.yml
|
|
9
9
|
var require_zh_CN_schema = __commonJS({
|
|
10
10
|
"src/locales/zh-CN.schema.yml"(exports, module) {
|
|
11
|
-
module.exports = { $inner: [{}, { $desc: "请求选项", platform: "适配器的平台名。(不懂请不要修改)", apiKeys: { $inner: ["Gemini 的 API Key", "Gemini API 的请求地址"], $desc: "Gemini 的 API Key 和请求地址列表。" } }, { $desc: "模型配置", maxTokens: "输入的最大上下文 Token(16~2097000,必须是 16 的倍数)。注意:仅当您使用的模型最大 Token 为 8000 及以上时,才建议设置超过 2000 token。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。", googleSearch: "为模型启用谷歌搜索。", thinkingBudget: "思考预算,范围:(-1~24576),设置的数值越大,思考时花费的 Token 越多,-1
|
|
11
|
+
module.exports = { $inner: [{}, { $desc: "请求选项", platform: "适配器的平台名。(不懂请不要修改)", apiKeys: { $inner: ["Gemini 的 API Key", "Gemini API 的请求地址"], $desc: "Gemini 的 API Key 和请求地址列表。" } }, { $desc: "模型配置", maxTokens: "输入的最大上下文 Token(16~2097000,必须是 16 的倍数)。注意:仅当您使用的模型最大 Token 为 8000 及以上时,才建议设置超过 2000 token。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。", googleSearch: "为模型启用谷歌搜索。", thinkingBudget: "思考预算,范围:(-1~24576),设置的数值越大,思考时花费的 Token 越多,-1 为动态思考。目前仅支持 gemini 2.5 系列模型。", groundingContentDisplay: "是否显示谷歌搜索结果。", imageGeneration: "为模型启用图像生成。目前仅支持 `gemini-2.0-flash-exp` 模型。", searchThreshold: "搜索的[置信度阈值](https://ai.google.dev/gemini-api/docs/grounding?lang=rest#dynamic-retrieval),范围:0~1,设置的数值越低,则越倾向于使用谷歌搜索。(仅支持 `gemini-1.5` 系列模型。gemini 2.0 模型起使用动态的工具调用)", includeThoughts: "是否获取模型的思考内容。", codeExecution: "为模型启用代码执行工具。", urlContext: "为模型启用 URL 内容获取工具。" }] };
|
|
12
12
|
}
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
// src/locales/en-US.schema.yml
|
|
16
16
|
var require_en_US_schema = __commonJS({
|
|
17
17
|
"src/locales/en-US.schema.yml"(exports, module) {
|
|
18
|
-
module.exports = { $inner: [{}, { $desc: "API Configuration", platform: "Adapter platform name. (Do not modify if you do not understand)", apiKeys: { $inner: ["Gemini API Key", "Gemini API Endpoint (optional)"], $desc: "Gemini API access credentials" } }, { $desc: "Model Parameters", maxTokens: "Max output tokens (16-2097000, multiple of 16). >2000 for 8k+ models", temperature: "Sampling temperature (0-2). Higher: more random, Lower: more deterministic", googleSearch: "Enable Google search", thinkingBudget: "Thinking budget (-1-24576). (
|
|
18
|
+
module.exports = { $inner: [{}, { $desc: "API Configuration", platform: "Adapter platform name. (Do not modify if you do not understand)", apiKeys: { $inner: ["Gemini API Key", "Gemini API Endpoint (optional)"], $desc: "Gemini API access credentials" } }, { $desc: "Model Parameters", maxTokens: "Max output tokens (16-2097000, multiple of 16). >2000 for 8k+ models", temperature: "Sampling temperature (0-2). Higher: more random, Lower: more deterministic", googleSearch: "Enable Google search", thinkingBudget: "Thinking budget (-1-24576). (0: dynamic thinking) Higher: more tokens spent on thinking. Currently only supports `gemini-2.5` series models.", groundingContentDisplay: "Enable display of search results", imageGeneration: "Enable image generation (only for `gemini-2.0-flash-exp` model)", searchThreshold: "Search confidence [threshold](https://ai.google.dev/gemini-api/docs/grounding?lang=rest#dynamic-retrieval) (0-1). Lower: more likely to use Google search", includeThoughts: "Enable retrieval of model thoughts", codeExecution: "Enable code execution tool", urlContext: "Enable URL context retrieval tool" }] };
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
} from "@langchain/core/messages";
|
|
60
60
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
61
61
|
async function langchainMessageToGeminiMessage(messages, model) {
|
|
62
|
-
const
|
|
62
|
+
const mappedMessages = await Promise.all(
|
|
63
63
|
messages.map(async (rawMessage) => {
|
|
64
64
|
const role = messageTypeToGeminiRole(rawMessage.getType());
|
|
65
65
|
if (role === "function" || rawMessage.additional_kwargs?.function_call != null) {
|
|
@@ -73,15 +73,15 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
73
73
|
name: rawMessage.name,
|
|
74
74
|
content: (() => {
|
|
75
75
|
try {
|
|
76
|
-
const
|
|
76
|
+
const result2 = JSON.parse(
|
|
77
77
|
rawMessage.content
|
|
78
78
|
);
|
|
79
|
-
if (typeof
|
|
79
|
+
if (typeof result2 === "string") {
|
|
80
80
|
return {
|
|
81
|
-
response:
|
|
81
|
+
response: result2
|
|
82
82
|
};
|
|
83
83
|
} else {
|
|
84
|
-
return
|
|
84
|
+
return result2;
|
|
85
85
|
}
|
|
86
86
|
} catch (e) {
|
|
87
87
|
return {
|
|
@@ -95,15 +95,15 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
95
95
|
name: rawMessage.additional_kwargs.function_call.name,
|
|
96
96
|
args: (() => {
|
|
97
97
|
try {
|
|
98
|
-
const
|
|
98
|
+
const result2 = JSON.parse(
|
|
99
99
|
rawMessage.additional_kwargs.function_call.arguments
|
|
100
100
|
);
|
|
101
|
-
if (typeof
|
|
101
|
+
if (typeof result2 === "string") {
|
|
102
102
|
return {
|
|
103
|
-
input:
|
|
103
|
+
input: result2
|
|
104
104
|
};
|
|
105
105
|
} else {
|
|
106
|
-
return
|
|
106
|
+
return result2;
|
|
107
107
|
}
|
|
108
108
|
} catch (e) {
|
|
109
109
|
return {
|
|
@@ -117,7 +117,7 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
119
|
const images = rawMessage.additional_kwargs.images;
|
|
120
|
-
const
|
|
120
|
+
const result = {
|
|
121
121
|
role,
|
|
122
122
|
parts: [
|
|
123
123
|
{
|
|
@@ -129,7 +129,7 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
129
129
|
for (const image of images) {
|
|
130
130
|
const mineType = image.split(";")?.[0]?.split(":")?.[1];
|
|
131
131
|
const data = image.replace(/^data:image\/\w+;base64,/, "");
|
|
132
|
-
|
|
132
|
+
result.parts.push({
|
|
133
133
|
inline_data: {
|
|
134
134
|
// base64 image match type
|
|
135
135
|
data,
|
|
@@ -137,7 +137,7 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
|
-
|
|
140
|
+
result.parts = result.parts.filter((uncheckedPart) => {
|
|
141
141
|
const part = partAsTypeCheck(
|
|
142
142
|
uncheckedPart,
|
|
143
143
|
(part2) => part2["text"] != null
|
|
@@ -145,54 +145,39 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
145
145
|
return part == null || part.text.length > 0;
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
|
-
return
|
|
148
|
+
return result;
|
|
149
149
|
})
|
|
150
150
|
);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
parts: message.parts
|
|
161
|
-
});
|
|
162
|
-
const nextMessage = mappedMessage?.[i + 1];
|
|
163
|
-
if (nextMessage?.role === "model") {
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
if (nextMessage?.role === "user" || nextMessage?.role === "system") {
|
|
167
|
-
result.push({
|
|
168
|
-
role: "model",
|
|
169
|
-
parts: [{ text: "Okay, what do I need to do?" }]
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
if (nextMessage?.role === "system") {
|
|
173
|
-
result.push({
|
|
174
|
-
role: "user",
|
|
175
|
-
parts: [
|
|
176
|
-
{
|
|
177
|
-
text: "Continue what I said to you last message. Follow these instructions."
|
|
178
|
-
}
|
|
179
|
-
]
|
|
180
|
-
});
|
|
151
|
+
return mappedMessages;
|
|
152
|
+
}
|
|
153
|
+
__name(langchainMessageToGeminiMessage, "langchainMessageToGeminiMessage");
|
|
154
|
+
function extractSystemMessages(messages) {
|
|
155
|
+
let lastSystemMessage;
|
|
156
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
157
|
+
if (messages[i].role === "system") {
|
|
158
|
+
lastSystemMessage = messages[i];
|
|
159
|
+
break;
|
|
181
160
|
}
|
|
182
161
|
}
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
role: "user",
|
|
186
|
-
parts: [
|
|
187
|
-
{
|
|
188
|
-
text: "Continue what I said to you last message. Follow these instructions."
|
|
189
|
-
}
|
|
190
|
-
]
|
|
191
|
-
});
|
|
162
|
+
if (lastSystemMessage == null) {
|
|
163
|
+
return [void 0, messages];
|
|
192
164
|
}
|
|
193
|
-
|
|
165
|
+
const systemMessages = messages.slice(
|
|
166
|
+
0,
|
|
167
|
+
messages.indexOf(lastSystemMessage)
|
|
168
|
+
);
|
|
169
|
+
return [
|
|
170
|
+
{
|
|
171
|
+
role: "user",
|
|
172
|
+
parts: systemMessages.reduce((acc, cur) => {
|
|
173
|
+
acc.push(...cur.parts);
|
|
174
|
+
return acc;
|
|
175
|
+
}, [])
|
|
176
|
+
},
|
|
177
|
+
messages.slice(messages.indexOf(lastSystemMessage))
|
|
178
|
+
];
|
|
194
179
|
}
|
|
195
|
-
__name(
|
|
180
|
+
__name(extractSystemMessages, "extractSystemMessages");
|
|
196
181
|
function partAsType(part) {
|
|
197
182
|
return part;
|
|
198
183
|
}
|
|
@@ -338,16 +323,24 @@ var GeminiRequester = class extends ModelRequester {
|
|
|
338
323
|
let model = params.model;
|
|
339
324
|
let enabledThinking = null;
|
|
340
325
|
if (model.includes("-thinking") && model.includes("gemini-2.5")) {
|
|
341
|
-
enabledThinking = !model.includes("-
|
|
342
|
-
model = model.replace("-
|
|
326
|
+
enabledThinking = !model.includes("-non-thinking");
|
|
327
|
+
model = model.replace("-nom-thinking", "").replace("-thinking", "");
|
|
328
|
+
}
|
|
329
|
+
const geminiMessages = await langchainMessageToGeminiMessage(
|
|
330
|
+
params.input,
|
|
331
|
+
model
|
|
332
|
+
);
|
|
333
|
+
const [systemInstruction, modelMessages] = extractSystemMessages(geminiMessages);
|
|
334
|
+
let thinkingBudget = this._pluginConfig.thinkingBudget ?? -1;
|
|
335
|
+
if (!enabledThinking && !model.includes("2.5-pro")) {
|
|
336
|
+
thinkingBudget = 0;
|
|
337
|
+
} else if (thinkingBudget >= 0 && thinkingBudget < 128) {
|
|
338
|
+
thinkingBudget = 128;
|
|
343
339
|
}
|
|
344
340
|
const response = await this._post(
|
|
345
341
|
`models/${model}:streamGenerateContent?alt=sse`,
|
|
346
342
|
{
|
|
347
|
-
contents:
|
|
348
|
-
params.input,
|
|
349
|
-
model
|
|
350
|
-
),
|
|
343
|
+
contents: modelMessages,
|
|
351
344
|
safetySettings: [
|
|
352
345
|
{
|
|
353
346
|
category: "HARM_CATEGORY_HARASSMENT",
|
|
@@ -380,10 +373,11 @@ var GeminiRequester = class extends ModelRequester {
|
|
|
380
373
|
"gemini-2.0-flash-exp"
|
|
381
374
|
) && this._pluginConfig.imageGeneration ? ["TEXT", "IMAGE"] : void 0,
|
|
382
375
|
thinkingConfig: enabledThinking != null || this._pluginConfig.includeThoughts ? {
|
|
383
|
-
thinkingBudget
|
|
376
|
+
thinkingBudget,
|
|
384
377
|
includeThoughts: this._pluginConfig.includeThoughts
|
|
385
378
|
} : void 0
|
|
386
379
|
},
|
|
380
|
+
systemInstruction: systemInstruction != null ? systemInstruction : void 0,
|
|
387
381
|
tools: params.tools != null || this._pluginConfig.googleSearch || this._pluginConfig.codeExecution || this._pluginConfig.urlContext ? formatToolsToGeminiAITools(
|
|
388
382
|
params.tools ?? [],
|
|
389
383
|
this._pluginConfig,
|
|
@@ -396,7 +390,7 @@ var GeminiRequester = class extends ModelRequester {
|
|
|
396
390
|
);
|
|
397
391
|
let errorCount = 0;
|
|
398
392
|
let groundingContent = "";
|
|
399
|
-
let
|
|
393
|
+
let currentGroundingIndex = 0;
|
|
400
394
|
await checkResponse(response);
|
|
401
395
|
const readableStream = new ReadableStream({
|
|
402
396
|
async start(controller) {
|
|
@@ -427,7 +421,7 @@ var GeminiRequester = class extends ModelRequester {
|
|
|
427
421
|
controller.enqueue(part);
|
|
428
422
|
}
|
|
429
423
|
for (const source of candidate.groundingMetadata?.groundingChunks ?? []) {
|
|
430
|
-
groundingContent += `[^${
|
|
424
|
+
groundingContent += `[^${currentGroundingIndex++}]: [${source.web.title}](${source.web.uri})
|
|
431
425
|
`;
|
|
432
426
|
}
|
|
433
427
|
}
|
|
@@ -697,7 +691,7 @@ var GeminiClient = class extends PlatformModelAndEmbeddingsClient {
|
|
|
697
691
|
if (model.name.includes("gemini-2.5") && !model.name.includes("pro")) {
|
|
698
692
|
if (!model.name.includes("-thinking")) {
|
|
699
693
|
models.push(
|
|
700
|
-
{ ...info, name: model.name + "-
|
|
694
|
+
{ ...info, name: model.name + "-nonthinking" },
|
|
701
695
|
{ ...info, name: model.name + "-thinking" },
|
|
702
696
|
info
|
|
703
697
|
);
|
|
@@ -797,7 +791,7 @@ var Config3 = Schema.intersect([
|
|
|
797
791
|
googleSearch: Schema.boolean().default(false),
|
|
798
792
|
codeExecution: Schema.boolean().default(false),
|
|
799
793
|
urlContext: Schema.boolean().default(false),
|
|
800
|
-
thinkingBudget: Schema.number().min(
|
|
794
|
+
thinkingBudget: Schema.number().min(-1).max(24576).default(-1),
|
|
801
795
|
includeThoughts: Schema.boolean().default(false),
|
|
802
796
|
imageGeneration: Schema.boolean().default(false),
|
|
803
797
|
groundingContentDisplay: Schema.boolean().default(false),
|
package/lib/utils.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { StructuredTool } from '@langchain/core/tools';
|
|
|
3
3
|
import { ChatCompletionFunction, ChatCompletionResponseMessage, ChatCompletionResponseMessageRoleEnum, ChatPart } from './types';
|
|
4
4
|
import { Config } from '.';
|
|
5
5
|
export declare function langchainMessageToGeminiMessage(messages: BaseMessage[], model?: string): Promise<ChatCompletionResponseMessage[]>;
|
|
6
|
+
export declare function extractSystemMessages(messages: ChatCompletionResponseMessage[]): [ChatCompletionResponseMessage, ChatCompletionResponseMessage[]];
|
|
6
7
|
export declare function partAsType<T extends ChatPart>(part: ChatPart): T;
|
|
7
8
|
export declare function partAsTypeCheck<T extends ChatPart>(part: ChatPart, check: (part: ChatPart & unknown) => boolean): T | undefined;
|
|
8
9
|
export declare function formatToolsToGeminiAITools(tools: StructuredTool[], config: Config, model: string): Record<string, any>;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-chatluna-google-gemini-adapter",
|
|
3
3
|
"description": "google-gemini adapter for chatluna",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.8",
|
|
5
5
|
"main": "lib/index.cjs",
|
|
6
6
|
"module": "lib/index.mjs",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"koishi": "^4.18.7",
|
|
75
|
-
"koishi-plugin-chatluna": "^1.3.0-alpha.
|
|
75
|
+
"koishi-plugin-chatluna": "^1.3.0-alpha.7"
|
|
76
76
|
},
|
|
77
77
|
"koishi": {
|
|
78
78
|
"description": {
|