koishi-plugin-chatluna-google-gemini-adapter 1.3.8 → 1.3.10
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/client.d.ts +2 -2
- package/lib/index.cjs +82 -41
- package/lib/index.mjs +59 -18
- package/lib/requester.d.ts +3 -2
- package/lib/utils.d.ts +16 -15
- package/package.json +3 -3
package/lib/client.d.ts
CHANGED
|
@@ -8,11 +8,11 @@ import { ChatLunaPlugin } from 'koishi-plugin-chatluna/services/chat';
|
|
|
8
8
|
import { RunnableConfig } from '@langchain/core/runnables';
|
|
9
9
|
export declare class GeminiClient extends PlatformModelAndEmbeddingsClient<ClientConfig> {
|
|
10
10
|
private _config;
|
|
11
|
-
plugin: ChatLunaPlugin
|
|
11
|
+
plugin: ChatLunaPlugin<ClientConfig, Config>;
|
|
12
12
|
platform: string;
|
|
13
13
|
private _requester;
|
|
14
14
|
get logger(): import("reggol");
|
|
15
|
-
constructor(ctx: Context, _config: Config, plugin: ChatLunaPlugin);
|
|
15
|
+
constructor(ctx: Context, _config: Config, plugin: ChatLunaPlugin<ClientConfig, Config>);
|
|
16
16
|
refreshModels(config?: RunnableConfig): Promise<ModelInfo[]>;
|
|
17
17
|
protected _createModel(model: string): ChatLunaChatModel | ChatLunaBaseEmbeddings;
|
|
18
18
|
}
|
package/lib/index.cjs
CHANGED
|
@@ -23,14 +23,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
23
23
|
// src/locales/zh-CN.schema.yml
|
|
24
24
|
var require_zh_CN_schema = __commonJS({
|
|
25
25
|
"src/locales/zh-CN.schema.yml"(exports2, module2) {
|
|
26
|
-
module2.exports = { $inner: [{}, { $desc: "请求选项", platform: "适配器的平台名。(不懂请不要修改)", apiKeys: { $inner: ["Gemini API Key", "Gemini API 请求地址", "是否启用此配置"], $desc: "Gemini 的 API Key 和请求地址列表。" } }, { $desc: "模型配置", maxContextRatio: "最大上下文使用比例(0~1),控制可用的模型上下文窗口大小的最大百分比。例如 0.35 表示最多使用模型上下文的 35%。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。", googleSearch: "为模型启用谷歌搜索。", thinkingBudget: "思考预算,范围:(-1~24576),设置的数值越大,思考时花费的 Token 越多,-1 为动态思考。目前仅支持 gemini 2.5 系列模型。", groundingContentDisplay: "是否显示谷歌搜索结果。", imageGeneration: "为模型启用图像生成。目前仅支持 `gemini
|
|
26
|
+
module2.exports = { $inner: [{}, { $desc: "请求选项", platform: "适配器的平台名。(不懂请不要修改)", apiKeys: { $inner: ["Gemini API Key", "Gemini API 请求地址", "是否启用此配置"], $desc: "Gemini 的 API Key 和请求地址列表。" } }, { $desc: "模型配置", maxContextRatio: "最大上下文使用比例(0~1),控制可用的模型上下文窗口大小的最大百分比。例如 0.35 表示最多使用模型上下文的 35%。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。", googleSearch: "为模型启用谷歌搜索。(开启后将无法使用工具调用)", thinkingBudget: "思考预算,范围:(-1~24576),设置的数值越大,思考时花费的 Token 越多,-1 为动态思考。目前仅支持 gemini 2.5 系列模型。", groundingContentDisplay: "是否显示谷歌搜索结果。", imageGeneration: "为模型启用图像生成。目前仅支持 `gemini-*-image-*` 和 `gemini-2.5-flash-image-preview` 模型。", 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 内容获取工具。", nonStreaming: "强制不启用流式返回。开启后,将总是以非流式发起请求,即便配置了 stream 参数。", useCamelCaseSystemInstruction: "使用大写的 systemInstruction 而不是小写的 system_instruction" }] };
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
// src/locales/en-US.schema.yml
|
|
31
31
|
var require_en_US_schema = __commonJS({
|
|
32
32
|
"src/locales/en-US.schema.yml"(exports2, module2) {
|
|
33
|
-
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)", "Enabled"], $desc: "Gemini API access credentials" } }, { $desc: "Model Parameters", maxContextRatio: "Maximum context usage ratio (0-1). Controls the maximum percentage of model context window available for use. For example, 0.35 means at most 35% of the model context can be used.", 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
|
|
33
|
+
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)", "Enabled"], $desc: "Gemini API access credentials" } }, { $desc: "Model Parameters", maxContextRatio: "Maximum context usage ratio (0-1). Controls the maximum percentage of model context window available for use. For example, 0.35 means at most 35% of the model context can be used.", 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-*-image-*` and `gemini-2.5-flash-image-preview` 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", nonStreaming: "Force disable streaming response. When enabled, requests will always be made in non-streaming mode, even if the stream parameter is configured.", useCamelCaseSystemInstruction: "Use camelCase systemInstruction instead of snake_case system_instruction" }] };
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
|
|
@@ -46,7 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
});
|
|
47
47
|
module.exports = __toCommonJS(index_exports);
|
|
48
48
|
var import_chat = require("koishi-plugin-chatluna/services/chat");
|
|
49
|
-
var
|
|
49
|
+
var import_koishi = require("koishi");
|
|
50
50
|
|
|
51
51
|
// src/client.ts
|
|
52
52
|
var import_client = require("koishi-plugin-chatluna/llm-core/platform/client");
|
|
@@ -67,14 +67,18 @@ var import_v1_shared_adapter = require("@chatluna/v1-shared-adapter");
|
|
|
67
67
|
var import_string = require("koishi-plugin-chatluna/utils/string");
|
|
68
68
|
var import_types = require("@langchain/core/utils/types");
|
|
69
69
|
var import_zod_openapi = require("@anatine/zod-openapi");
|
|
70
|
-
var
|
|
70
|
+
var import_object = require("koishi-plugin-chatluna/utils/object");
|
|
71
71
|
async function langchainMessageToGeminiMessage(messages, plugin, model) {
|
|
72
72
|
return Promise.all(
|
|
73
73
|
messages.map(async (message) => {
|
|
74
74
|
const role = messageTypeToGeminiRole(message.getType());
|
|
75
75
|
const hasFunctionCall = message.tool_calls != null && message.tool_calls.length > 0;
|
|
76
76
|
if (role === "function" || hasFunctionCall) {
|
|
77
|
-
return processFunctionMessage(
|
|
77
|
+
return processFunctionMessage(
|
|
78
|
+
message,
|
|
79
|
+
// 如果使用 new api,我们应该去掉 id,,,
|
|
80
|
+
plugin.config.useCamelCaseSystemInstruction
|
|
81
|
+
);
|
|
78
82
|
}
|
|
79
83
|
const result = {
|
|
80
84
|
role,
|
|
@@ -134,7 +138,7 @@ function parseJsonArgs(args) {
|
|
|
134
138
|
}
|
|
135
139
|
}
|
|
136
140
|
__name(parseJsonArgs, "parseJsonArgs");
|
|
137
|
-
function processFunctionMessage(message) {
|
|
141
|
+
function processFunctionMessage(message, removeId) {
|
|
138
142
|
const thoughtData = message.additional_kwargs["thought_data"] ?? {};
|
|
139
143
|
if (message["tool_calls"]) {
|
|
140
144
|
message = message;
|
|
@@ -142,27 +146,33 @@ function processFunctionMessage(message) {
|
|
|
142
146
|
return {
|
|
143
147
|
role: "model",
|
|
144
148
|
parts: toolCalls.map((toolCall) => {
|
|
149
|
+
const functionCall = {
|
|
150
|
+
name: toolCall.name,
|
|
151
|
+
args: toolCall.args
|
|
152
|
+
};
|
|
153
|
+
if (!removeId) {
|
|
154
|
+
functionCall.id = toolCall.id;
|
|
155
|
+
}
|
|
145
156
|
return {
|
|
146
|
-
functionCall
|
|
147
|
-
name: toolCall.name,
|
|
148
|
-
args: toolCall.args,
|
|
149
|
-
id: toolCall.id
|
|
150
|
-
},
|
|
157
|
+
functionCall,
|
|
151
158
|
...thoughtData
|
|
152
159
|
};
|
|
153
160
|
})
|
|
154
161
|
};
|
|
155
162
|
}
|
|
156
163
|
const finalMessage = message;
|
|
164
|
+
const functionResponse = {
|
|
165
|
+
name: message.name,
|
|
166
|
+
response: parseJsonArgs(message.content)
|
|
167
|
+
};
|
|
168
|
+
if (!removeId) {
|
|
169
|
+
functionResponse.id = finalMessage.tool_call_id;
|
|
170
|
+
}
|
|
157
171
|
return {
|
|
158
172
|
role: "user",
|
|
159
173
|
parts: [
|
|
160
174
|
{
|
|
161
|
-
functionResponse
|
|
162
|
-
name: message.name,
|
|
163
|
-
id: finalMessage.tool_call_id,
|
|
164
|
-
response: parseJsonArgs(message.content)
|
|
165
|
-
}
|
|
175
|
+
functionResponse
|
|
166
176
|
}
|
|
167
177
|
]
|
|
168
178
|
};
|
|
@@ -324,6 +334,7 @@ function prepareModelConfig(params, pluginConfig) {
|
|
|
324
334
|
let model = params.model;
|
|
325
335
|
let enabledThinking = null;
|
|
326
336
|
let thinkingLevel = "THINKING_LEVEL_UNSPECIFIED";
|
|
337
|
+
let imageSize;
|
|
327
338
|
if (model.includes("-thinking") && model.includes("gemini-2.5")) {
|
|
328
339
|
enabledThinking = !model.includes("-non-thinking");
|
|
329
340
|
model = model.replace("-non-thinking", "").replace("-thinking", "");
|
|
@@ -348,6 +359,11 @@ function prepareModelConfig(params, pluginConfig) {
|
|
|
348
359
|
} else {
|
|
349
360
|
thinkingLevel = void 0;
|
|
350
361
|
}
|
|
362
|
+
const imageSizeMatch = model.match(/-(2K|4K)$/);
|
|
363
|
+
if (imageSizeMatch) {
|
|
364
|
+
imageSize = imageSizeMatch[1];
|
|
365
|
+
model = model.replace(`-${imageSize}`, "");
|
|
366
|
+
}
|
|
351
367
|
let imageGeneration = pluginConfig.imageGeneration ?? false;
|
|
352
368
|
if (imageGeneration) {
|
|
353
369
|
imageGeneration = params.model.includes("gemini-2.0-flash-exp") || params.model.includes("image");
|
|
@@ -357,7 +373,8 @@ function prepareModelConfig(params, pluginConfig) {
|
|
|
357
373
|
enabledThinking,
|
|
358
374
|
thinkingBudget,
|
|
359
375
|
imageGeneration,
|
|
360
|
-
thinkingLevel
|
|
376
|
+
thinkingLevel,
|
|
377
|
+
imageSize
|
|
361
378
|
};
|
|
362
379
|
}
|
|
363
380
|
__name(prepareModelConfig, "prepareModelConfig");
|
|
@@ -388,21 +405,25 @@ function createSafetySettings(model) {
|
|
|
388
405
|
}
|
|
389
406
|
__name(createSafetySettings, "createSafetySettings");
|
|
390
407
|
function createGenerationConfig(params, modelConfig, pluginConfig) {
|
|
391
|
-
|
|
408
|
+
const base = {
|
|
392
409
|
stopSequences: params.stop,
|
|
393
410
|
temperature: params.temperature,
|
|
394
411
|
maxOutputTokens: params.model.includes("vision") ? void 0 : params.maxTokens,
|
|
395
412
|
topP: params.topP,
|
|
396
413
|
responseModalities: modelConfig.imageGeneration ? ["TEXT", "IMAGE"] : void 0,
|
|
397
|
-
|
|
414
|
+
imageConfig: modelConfig.imageSize ? {
|
|
415
|
+
imageSize: modelConfig.imageSize
|
|
416
|
+
} : void 0,
|
|
417
|
+
thinkingConfig: modelConfig.enabledThinking != null || pluginConfig.includeThoughts ? filterKeys(
|
|
398
418
|
{
|
|
399
419
|
thinkingBudget: modelConfig.thinkingBudget,
|
|
400
420
|
thinkingLevel: modelConfig.thinkingLevel,
|
|
401
421
|
includeThoughts: pluginConfig.includeThoughts
|
|
402
422
|
},
|
|
403
|
-
|
|
423
|
+
notNullFn
|
|
404
424
|
) : void 0
|
|
405
425
|
};
|
|
426
|
+
return (0, import_object.deepAssign)({}, base, params.overrideRequestParams ?? {});
|
|
406
427
|
}
|
|
407
428
|
__name(createGenerationConfig, "createGenerationConfig");
|
|
408
429
|
async function createChatGenerationParams(params, plugin, modelConfig, pluginConfig) {
|
|
@@ -434,6 +455,16 @@ function isChatResponse(response) {
|
|
|
434
455
|
return "candidates" in response;
|
|
435
456
|
}
|
|
436
457
|
__name(isChatResponse, "isChatResponse");
|
|
458
|
+
function notNullFn(_, v) {
|
|
459
|
+
return v != null;
|
|
460
|
+
}
|
|
461
|
+
__name(notNullFn, "notNullFn");
|
|
462
|
+
function filterKeys(obj, fn) {
|
|
463
|
+
return Object.fromEntries(
|
|
464
|
+
Object.entries(obj).filter(([k, v]) => fn(k, v))
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
__name(filterKeys, "filterKeys");
|
|
437
468
|
|
|
438
469
|
// src/requester.ts
|
|
439
470
|
var import_string2 = require("koishi-plugin-chatluna/utils/string");
|
|
@@ -442,6 +473,7 @@ var GeminiRequester = class extends import_api.ModelRequester {
|
|
|
442
473
|
constructor(ctx, _configPool, _pluginConfig, _plugin) {
|
|
443
474
|
super(ctx, _configPool, _pluginConfig, _plugin);
|
|
444
475
|
this._pluginConfig = _pluginConfig;
|
|
476
|
+
this._plugin = _plugin;
|
|
445
477
|
}
|
|
446
478
|
static {
|
|
447
479
|
__name(this, "GeminiRequester");
|
|
@@ -1009,6 +1041,7 @@ var GeminiClient = class extends import_client.PlatformModelAndEmbeddingsClient
|
|
|
1009
1041
|
};
|
|
1010
1042
|
const thinkingModel = ["gemini-2.5-pro", "gemini-2.5-flash"];
|
|
1011
1043
|
const thinkingLevelModel = ["gemini-3.0-pro"];
|
|
1044
|
+
const imageResolutionModel = ["gemini-3.0-pro-image"];
|
|
1012
1045
|
if (thinkingModel.some(
|
|
1013
1046
|
(name2) => model.name.toLowerCase().includes(name2) && !model.name.toLowerCase().includes("image")
|
|
1014
1047
|
)) {
|
|
@@ -1028,6 +1061,14 @@ var GeminiClient = class extends import_client.PlatformModelAndEmbeddingsClient
|
|
|
1028
1061
|
{ ...info, name: model.name + "-low-thinking" },
|
|
1029
1062
|
info
|
|
1030
1063
|
);
|
|
1064
|
+
} else if (imageResolutionModel.some(
|
|
1065
|
+
(name2) => model.name.toLowerCase().includes(name2)
|
|
1066
|
+
)) {
|
|
1067
|
+
models.push(
|
|
1068
|
+
{ ...info, name: model.name + "-2K" },
|
|
1069
|
+
{ ...info, name: model.name + "-4K" },
|
|
1070
|
+
info
|
|
1071
|
+
);
|
|
1031
1072
|
} else {
|
|
1032
1073
|
models.push(info);
|
|
1033
1074
|
}
|
|
@@ -1096,33 +1137,33 @@ function apply(ctx, config) {
|
|
|
1096
1137
|
});
|
|
1097
1138
|
}
|
|
1098
1139
|
__name(apply, "apply");
|
|
1099
|
-
var Config4 =
|
|
1140
|
+
var Config4 = import_koishi.Schema.intersect([
|
|
1100
1141
|
import_chat.ChatLunaPlugin.Config,
|
|
1101
|
-
|
|
1102
|
-
platform:
|
|
1103
|
-
apiKeys:
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1142
|
+
import_koishi.Schema.object({
|
|
1143
|
+
platform: import_koishi.Schema.string().default("gemini"),
|
|
1144
|
+
apiKeys: import_koishi.Schema.array(
|
|
1145
|
+
import_koishi.Schema.tuple([
|
|
1146
|
+
import_koishi.Schema.string().role("secret").default(""),
|
|
1147
|
+
import_koishi.Schema.string().default(
|
|
1107
1148
|
"https://generativelanguage.googleapis.com/v1beta"
|
|
1108
1149
|
),
|
|
1109
|
-
|
|
1150
|
+
import_koishi.Schema.boolean().default(true)
|
|
1110
1151
|
])
|
|
1111
1152
|
).default([[]]).role("table")
|
|
1112
1153
|
}),
|
|
1113
|
-
|
|
1114
|
-
maxContextRatio:
|
|
1115
|
-
temperature:
|
|
1116
|
-
googleSearch:
|
|
1117
|
-
codeExecution:
|
|
1118
|
-
urlContext:
|
|
1119
|
-
thinkingBudget:
|
|
1120
|
-
includeThoughts:
|
|
1121
|
-
nonStreaming:
|
|
1122
|
-
imageGeneration:
|
|
1123
|
-
groundingContentDisplay:
|
|
1124
|
-
searchThreshold:
|
|
1125
|
-
useCamelCaseSystemInstruction:
|
|
1154
|
+
import_koishi.Schema.object({
|
|
1155
|
+
maxContextRatio: import_koishi.Schema.number().min(0).max(1).step(1e-4).role("slider").default(0.35),
|
|
1156
|
+
temperature: import_koishi.Schema.percent().min(0).max(2).step(0.1).default(1),
|
|
1157
|
+
googleSearch: import_koishi.Schema.boolean().default(false),
|
|
1158
|
+
codeExecution: import_koishi.Schema.boolean().default(false),
|
|
1159
|
+
urlContext: import_koishi.Schema.boolean().default(false),
|
|
1160
|
+
thinkingBudget: import_koishi.Schema.number().min(-1).max(24576).default(-1),
|
|
1161
|
+
includeThoughts: import_koishi.Schema.boolean().default(false),
|
|
1162
|
+
nonStreaming: import_koishi.Schema.boolean().default(false),
|
|
1163
|
+
imageGeneration: import_koishi.Schema.boolean().default(false),
|
|
1164
|
+
groundingContentDisplay: import_koishi.Schema.boolean().default(false),
|
|
1165
|
+
searchThreshold: import_koishi.Schema.number().min(0).max(1).step(0.1).default(0.5),
|
|
1166
|
+
useCamelCaseSystemInstruction: import_koishi.Schema.boolean().default(false)
|
|
1126
1167
|
})
|
|
1127
1168
|
]).i18n({
|
|
1128
1169
|
"zh-CN": require_zh_CN_schema(),
|
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: "模型配置", maxContextRatio: "最大上下文使用比例(0~1),控制可用的模型上下文窗口大小的最大百分比。例如 0.35 表示最多使用模型上下文的 35%。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。", googleSearch: "为模型启用谷歌搜索。", thinkingBudget: "思考预算,范围:(-1~24576),设置的数值越大,思考时花费的 Token 越多,-1 为动态思考。目前仅支持 gemini 2.5 系列模型。", groundingContentDisplay: "是否显示谷歌搜索结果。", imageGeneration: "为模型启用图像生成。目前仅支持 `gemini
|
|
11
|
+
module.exports = { $inner: [{}, { $desc: "请求选项", platform: "适配器的平台名。(不懂请不要修改)", apiKeys: { $inner: ["Gemini API Key", "Gemini API 请求地址", "是否启用此配置"], $desc: "Gemini 的 API Key 和请求地址列表。" } }, { $desc: "模型配置", maxContextRatio: "最大上下文使用比例(0~1),控制可用的模型上下文窗口大小的最大百分比。例如 0.35 表示最多使用模型上下文的 35%。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。", googleSearch: "为模型启用谷歌搜索。(开启后将无法使用工具调用)", thinkingBudget: "思考预算,范围:(-1~24576),设置的数值越大,思考时花费的 Token 越多,-1 为动态思考。目前仅支持 gemini 2.5 系列模型。", groundingContentDisplay: "是否显示谷歌搜索结果。", imageGeneration: "为模型启用图像生成。目前仅支持 `gemini-*-image-*` 和 `gemini-2.5-flash-image-preview` 模型。", 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 内容获取工具。", nonStreaming: "强制不启用流式返回。开启后,将总是以非流式发起请求,即便配置了 stream 参数。", useCamelCaseSystemInstruction: "使用大写的 systemInstruction 而不是小写的 system_instruction" }] };
|
|
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)", "Enabled"], $desc: "Gemini API access credentials" } }, { $desc: "Model Parameters", maxContextRatio: "Maximum context usage ratio (0-1). Controls the maximum percentage of model context window available for use. For example, 0.35 means at most 35% of the model context can be used.", 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
|
|
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)", "Enabled"], $desc: "Gemini API access credentials" } }, { $desc: "Model Parameters", maxContextRatio: "Maximum context usage ratio (0-1). Controls the maximum percentage of model context window available for use. For example, 0.35 means at most 35% of the model context can be used.", 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-*-image-*` and `gemini-2.5-flash-image-preview` 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", nonStreaming: "Force disable streaming response. When enabled, requests will always be made in non-streaming mode, even if the stream parameter is configured.", useCamelCaseSystemInstruction: "Use camelCase systemInstruction instead of snake_case system_instruction" }] };
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
21
|
|
|
@@ -64,14 +64,18 @@ import {
|
|
|
64
64
|
} from "koishi-plugin-chatluna/utils/string";
|
|
65
65
|
import { isZodSchemaV3 } from "@langchain/core/utils/types";
|
|
66
66
|
import { generateSchema } from "@anatine/zod-openapi";
|
|
67
|
-
import {
|
|
67
|
+
import { deepAssign } from "koishi-plugin-chatluna/utils/object";
|
|
68
68
|
async function langchainMessageToGeminiMessage(messages, plugin, model) {
|
|
69
69
|
return Promise.all(
|
|
70
70
|
messages.map(async (message) => {
|
|
71
71
|
const role = messageTypeToGeminiRole(message.getType());
|
|
72
72
|
const hasFunctionCall = message.tool_calls != null && message.tool_calls.length > 0;
|
|
73
73
|
if (role === "function" || hasFunctionCall) {
|
|
74
|
-
return processFunctionMessage(
|
|
74
|
+
return processFunctionMessage(
|
|
75
|
+
message,
|
|
76
|
+
// 如果使用 new api,我们应该去掉 id,,,
|
|
77
|
+
plugin.config.useCamelCaseSystemInstruction
|
|
78
|
+
);
|
|
75
79
|
}
|
|
76
80
|
const result = {
|
|
77
81
|
role,
|
|
@@ -131,7 +135,7 @@ function parseJsonArgs(args) {
|
|
|
131
135
|
}
|
|
132
136
|
}
|
|
133
137
|
__name(parseJsonArgs, "parseJsonArgs");
|
|
134
|
-
function processFunctionMessage(message) {
|
|
138
|
+
function processFunctionMessage(message, removeId) {
|
|
135
139
|
const thoughtData = message.additional_kwargs["thought_data"] ?? {};
|
|
136
140
|
if (message["tool_calls"]) {
|
|
137
141
|
message = message;
|
|
@@ -139,27 +143,33 @@ function processFunctionMessage(message) {
|
|
|
139
143
|
return {
|
|
140
144
|
role: "model",
|
|
141
145
|
parts: toolCalls.map((toolCall) => {
|
|
146
|
+
const functionCall = {
|
|
147
|
+
name: toolCall.name,
|
|
148
|
+
args: toolCall.args
|
|
149
|
+
};
|
|
150
|
+
if (!removeId) {
|
|
151
|
+
functionCall.id = toolCall.id;
|
|
152
|
+
}
|
|
142
153
|
return {
|
|
143
|
-
functionCall
|
|
144
|
-
name: toolCall.name,
|
|
145
|
-
args: toolCall.args,
|
|
146
|
-
id: toolCall.id
|
|
147
|
-
},
|
|
154
|
+
functionCall,
|
|
148
155
|
...thoughtData
|
|
149
156
|
};
|
|
150
157
|
})
|
|
151
158
|
};
|
|
152
159
|
}
|
|
153
160
|
const finalMessage = message;
|
|
161
|
+
const functionResponse = {
|
|
162
|
+
name: message.name,
|
|
163
|
+
response: parseJsonArgs(message.content)
|
|
164
|
+
};
|
|
165
|
+
if (!removeId) {
|
|
166
|
+
functionResponse.id = finalMessage.tool_call_id;
|
|
167
|
+
}
|
|
154
168
|
return {
|
|
155
169
|
role: "user",
|
|
156
170
|
parts: [
|
|
157
171
|
{
|
|
158
|
-
functionResponse
|
|
159
|
-
name: message.name,
|
|
160
|
-
id: finalMessage.tool_call_id,
|
|
161
|
-
response: parseJsonArgs(message.content)
|
|
162
|
-
}
|
|
172
|
+
functionResponse
|
|
163
173
|
}
|
|
164
174
|
]
|
|
165
175
|
};
|
|
@@ -321,6 +331,7 @@ function prepareModelConfig(params, pluginConfig) {
|
|
|
321
331
|
let model = params.model;
|
|
322
332
|
let enabledThinking = null;
|
|
323
333
|
let thinkingLevel = "THINKING_LEVEL_UNSPECIFIED";
|
|
334
|
+
let imageSize;
|
|
324
335
|
if (model.includes("-thinking") && model.includes("gemini-2.5")) {
|
|
325
336
|
enabledThinking = !model.includes("-non-thinking");
|
|
326
337
|
model = model.replace("-non-thinking", "").replace("-thinking", "");
|
|
@@ -345,6 +356,11 @@ function prepareModelConfig(params, pluginConfig) {
|
|
|
345
356
|
} else {
|
|
346
357
|
thinkingLevel = void 0;
|
|
347
358
|
}
|
|
359
|
+
const imageSizeMatch = model.match(/-(2K|4K)$/);
|
|
360
|
+
if (imageSizeMatch) {
|
|
361
|
+
imageSize = imageSizeMatch[1];
|
|
362
|
+
model = model.replace(`-${imageSize}`, "");
|
|
363
|
+
}
|
|
348
364
|
let imageGeneration = pluginConfig.imageGeneration ?? false;
|
|
349
365
|
if (imageGeneration) {
|
|
350
366
|
imageGeneration = params.model.includes("gemini-2.0-flash-exp") || params.model.includes("image");
|
|
@@ -354,7 +370,8 @@ function prepareModelConfig(params, pluginConfig) {
|
|
|
354
370
|
enabledThinking,
|
|
355
371
|
thinkingBudget,
|
|
356
372
|
imageGeneration,
|
|
357
|
-
thinkingLevel
|
|
373
|
+
thinkingLevel,
|
|
374
|
+
imageSize
|
|
358
375
|
};
|
|
359
376
|
}
|
|
360
377
|
__name(prepareModelConfig, "prepareModelConfig");
|
|
@@ -385,21 +402,25 @@ function createSafetySettings(model) {
|
|
|
385
402
|
}
|
|
386
403
|
__name(createSafetySettings, "createSafetySettings");
|
|
387
404
|
function createGenerationConfig(params, modelConfig, pluginConfig) {
|
|
388
|
-
|
|
405
|
+
const base = {
|
|
389
406
|
stopSequences: params.stop,
|
|
390
407
|
temperature: params.temperature,
|
|
391
408
|
maxOutputTokens: params.model.includes("vision") ? void 0 : params.maxTokens,
|
|
392
409
|
topP: params.topP,
|
|
393
410
|
responseModalities: modelConfig.imageGeneration ? ["TEXT", "IMAGE"] : void 0,
|
|
411
|
+
imageConfig: modelConfig.imageSize ? {
|
|
412
|
+
imageSize: modelConfig.imageSize
|
|
413
|
+
} : void 0,
|
|
394
414
|
thinkingConfig: modelConfig.enabledThinking != null || pluginConfig.includeThoughts ? filterKeys(
|
|
395
415
|
{
|
|
396
416
|
thinkingBudget: modelConfig.thinkingBudget,
|
|
397
417
|
thinkingLevel: modelConfig.thinkingLevel,
|
|
398
418
|
includeThoughts: pluginConfig.includeThoughts
|
|
399
419
|
},
|
|
400
|
-
|
|
420
|
+
notNullFn
|
|
401
421
|
) : void 0
|
|
402
422
|
};
|
|
423
|
+
return deepAssign({}, base, params.overrideRequestParams ?? {});
|
|
403
424
|
}
|
|
404
425
|
__name(createGenerationConfig, "createGenerationConfig");
|
|
405
426
|
async function createChatGenerationParams(params, plugin, modelConfig, pluginConfig) {
|
|
@@ -431,6 +452,16 @@ function isChatResponse(response) {
|
|
|
431
452
|
return "candidates" in response;
|
|
432
453
|
}
|
|
433
454
|
__name(isChatResponse, "isChatResponse");
|
|
455
|
+
function notNullFn(_, v) {
|
|
456
|
+
return v != null;
|
|
457
|
+
}
|
|
458
|
+
__name(notNullFn, "notNullFn");
|
|
459
|
+
function filterKeys(obj, fn) {
|
|
460
|
+
return Object.fromEntries(
|
|
461
|
+
Object.entries(obj).filter(([k, v]) => fn(k, v))
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
__name(filterKeys, "filterKeys");
|
|
434
465
|
|
|
435
466
|
// src/requester.ts
|
|
436
467
|
import { getMessageContent } from "koishi-plugin-chatluna/utils/string";
|
|
@@ -439,6 +470,7 @@ var GeminiRequester = class extends ModelRequester {
|
|
|
439
470
|
constructor(ctx, _configPool, _pluginConfig, _plugin) {
|
|
440
471
|
super(ctx, _configPool, _pluginConfig, _plugin);
|
|
441
472
|
this._pluginConfig = _pluginConfig;
|
|
473
|
+
this._plugin = _plugin;
|
|
442
474
|
}
|
|
443
475
|
static {
|
|
444
476
|
__name(this, "GeminiRequester");
|
|
@@ -1006,6 +1038,7 @@ var GeminiClient = class extends PlatformModelAndEmbeddingsClient {
|
|
|
1006
1038
|
};
|
|
1007
1039
|
const thinkingModel = ["gemini-2.5-pro", "gemini-2.5-flash"];
|
|
1008
1040
|
const thinkingLevelModel = ["gemini-3.0-pro"];
|
|
1041
|
+
const imageResolutionModel = ["gemini-3.0-pro-image"];
|
|
1009
1042
|
if (thinkingModel.some(
|
|
1010
1043
|
(name2) => model.name.toLowerCase().includes(name2) && !model.name.toLowerCase().includes("image")
|
|
1011
1044
|
)) {
|
|
@@ -1025,6 +1058,14 @@ var GeminiClient = class extends PlatformModelAndEmbeddingsClient {
|
|
|
1025
1058
|
{ ...info, name: model.name + "-low-thinking" },
|
|
1026
1059
|
info
|
|
1027
1060
|
);
|
|
1061
|
+
} else if (imageResolutionModel.some(
|
|
1062
|
+
(name2) => model.name.toLowerCase().includes(name2)
|
|
1063
|
+
)) {
|
|
1064
|
+
models.push(
|
|
1065
|
+
{ ...info, name: model.name + "-2K" },
|
|
1066
|
+
{ ...info, name: model.name + "-4K" },
|
|
1067
|
+
info
|
|
1068
|
+
);
|
|
1028
1069
|
} else {
|
|
1029
1070
|
models.push(info);
|
|
1030
1071
|
}
|
package/lib/requester.d.ts
CHANGED
|
@@ -6,9 +6,10 @@ import { GeminiModelInfo } from './types';
|
|
|
6
6
|
import { ChatLunaPlugin } from 'koishi-plugin-chatluna/services/chat';
|
|
7
7
|
import { Context } from 'koishi';
|
|
8
8
|
import { RunnableConfig } from '@langchain/core/runnables';
|
|
9
|
-
export declare class GeminiRequester extends ModelRequester implements EmbeddingsRequester {
|
|
9
|
+
export declare class GeminiRequester extends ModelRequester<ClientConfig, Config> implements EmbeddingsRequester {
|
|
10
10
|
_pluginConfig: Config;
|
|
11
|
-
|
|
11
|
+
_plugin: ChatLunaPlugin<ClientConfig, Config>;
|
|
12
|
+
constructor(ctx: Context, _configPool: ClientConfigPool<ClientConfig>, _pluginConfig: Config, _plugin: ChatLunaPlugin<ClientConfig, Config>);
|
|
12
13
|
completion(params: ModelRequestParams): Promise<ChatGeneration>;
|
|
13
14
|
completionStreamInternal(params: ModelRequestParams): AsyncGenerator<ChatGenerationChunk>;
|
|
14
15
|
completionInternal(params: ModelRequestParams): Promise<ChatGeneration>;
|
package/lib/utils.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ import { ChatCompletionFunction, ChatCompletionResponseMessage, ChatCompletionRe
|
|
|
4
4
|
import { Config } from '.';
|
|
5
5
|
import { ModelRequestParams } from 'koishi-plugin-chatluna/llm-core/platform/api';
|
|
6
6
|
import { ChatLunaPlugin } from 'koishi-plugin-chatluna/services/chat';
|
|
7
|
-
|
|
7
|
+
import { ClientConfig } from 'koishi-plugin-chatluna/llm-core/platform/config';
|
|
8
|
+
export declare function langchainMessageToGeminiMessage(messages: BaseMessage[], plugin: ChatLunaPlugin<ClientConfig, Config>, model?: string): Promise<ChatCompletionResponseMessage[]>;
|
|
8
9
|
export declare function extractSystemMessages(messages: ChatCompletionResponseMessage[]): [ChatCompletionResponseMessage, ChatCompletionResponseMessage[]];
|
|
9
10
|
export declare function partAsType<T extends ChatPart>(part: ChatPart): T;
|
|
10
11
|
export declare function partAsTypeCheck<T extends ChatPart>(part: ChatPart, check: (part: ChatPart & unknown) => boolean): T | undefined;
|
|
@@ -17,6 +18,7 @@ export declare function prepareModelConfig(params: ModelRequestParams, pluginCon
|
|
|
17
18
|
thinkingBudget: number;
|
|
18
19
|
imageGeneration: boolean;
|
|
19
20
|
thinkingLevel: string;
|
|
21
|
+
imageSize: string;
|
|
20
22
|
};
|
|
21
23
|
export declare function createSafetySettings(model: string): {
|
|
22
24
|
category: string;
|
|
@@ -28,20 +30,16 @@ export declare function createGenerationConfig(params: ModelRequestParams, model
|
|
|
28
30
|
maxOutputTokens: number;
|
|
29
31
|
topP: number;
|
|
30
32
|
responseModalities: string[];
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
topP: number;
|
|
39
|
-
responseModalities: string[];
|
|
40
|
-
thinkingConfig: import("cosmokit").Dict<string | number | boolean, "thinkingBudget" | "thinkingLevel" | "includeThoughts">;
|
|
41
|
-
} | ChatCompletionResponseMessage | ChatCompletionResponseMessage[] | {
|
|
33
|
+
imageConfig: {
|
|
34
|
+
imageSize: string;
|
|
35
|
+
};
|
|
36
|
+
thinkingConfig: Record<"thinkingBudget" | "thinkingLevel" | "includeThoughts", string | number | boolean>;
|
|
37
|
+
} & Record<string, any>;
|
|
38
|
+
export declare function createChatGenerationParams(params: ModelRequestParams, plugin: ChatLunaPlugin<ClientConfig, Config>, modelConfig: ReturnType<typeof prepareModelConfig>, pluginConfig: Config): Promise<{
|
|
39
|
+
[x: string]: Record<string, any> | ChatCompletionResponseMessage | ChatCompletionResponseMessage[] | {
|
|
42
40
|
category: string;
|
|
43
41
|
threshold: string;
|
|
44
|
-
}[]
|
|
42
|
+
}[];
|
|
45
43
|
contents: ChatCompletionResponseMessage[];
|
|
46
44
|
safetySettings: {
|
|
47
45
|
category: string;
|
|
@@ -53,8 +51,11 @@ export declare function createChatGenerationParams(params: ModelRequestParams, p
|
|
|
53
51
|
maxOutputTokens: number;
|
|
54
52
|
topP: number;
|
|
55
53
|
responseModalities: string[];
|
|
56
|
-
|
|
57
|
-
|
|
54
|
+
imageConfig: {
|
|
55
|
+
imageSize: string;
|
|
56
|
+
};
|
|
57
|
+
thinkingConfig: Record<"thinkingBudget" | "thinkingLevel" | "includeThoughts", string | number | boolean>;
|
|
58
|
+
} & Record<string, any>;
|
|
58
59
|
tools: Record<string, any>;
|
|
59
60
|
}>;
|
|
60
61
|
export declare function isChatResponse(response: any): response is ChatResponse;
|
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.3.
|
|
4
|
+
"version": "1.3.10",
|
|
5
5
|
"main": "lib/index.cjs",
|
|
6
6
|
"module": "lib/index.mjs",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
],
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@anatine/zod-openapi": "^2.2.8",
|
|
66
|
-
"@chatluna/v1-shared-adapter": "^1.0.
|
|
66
|
+
"@chatluna/v1-shared-adapter": "^1.0.17",
|
|
67
67
|
"@langchain/core": "0.3.62",
|
|
68
68
|
"openapi3-ts": "^4.5.0",
|
|
69
69
|
"zod": "3.25.76",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
},
|
|
76
76
|
"peerDependencies": {
|
|
77
77
|
"koishi": "^4.18.9",
|
|
78
|
-
"koishi-plugin-chatluna": "^1.3.
|
|
78
|
+
"koishi-plugin-chatluna": "^1.3.1",
|
|
79
79
|
"koishi-plugin-chatluna-storage-service": "^0.0.11"
|
|
80
80
|
},
|
|
81
81
|
"peerDependenciesMeta": {
|