koishi-plugin-chatluna-google-gemini-adapter 1.3.7 → 1.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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-2.0-flash-exp` 和 `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" }] };
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-2.0-flash-exp` 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" }] };
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 import_koishi2 = require("koishi");
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,16 @@ 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 import_koishi = require("koishi");
71
70
  async function langchainMessageToGeminiMessage(messages, plugin, model) {
72
71
  return Promise.all(
73
72
  messages.map(async (message) => {
74
73
  const role = messageTypeToGeminiRole(message.getType());
75
74
  const hasFunctionCall = message.tool_calls != null && message.tool_calls.length > 0;
76
75
  if (role === "function" || hasFunctionCall) {
77
- return processFunctionMessage(message);
76
+ return processFunctionMessage(
77
+ message,
78
+ plugin.config.useCamelCaseSystemInstruction
79
+ );
78
80
  }
79
81
  const result = {
80
82
  role,
@@ -134,7 +136,7 @@ function parseJsonArgs(args) {
134
136
  }
135
137
  }
136
138
  __name(parseJsonArgs, "parseJsonArgs");
137
- function processFunctionMessage(message) {
139
+ function processFunctionMessage(message, removeId) {
138
140
  const thoughtData = message.additional_kwargs["thought_data"] ?? {};
139
141
  if (message["tool_calls"]) {
140
142
  message = message;
@@ -142,27 +144,33 @@ function processFunctionMessage(message) {
142
144
  return {
143
145
  role: "model",
144
146
  parts: toolCalls.map((toolCall) => {
147
+ const functionCall = {
148
+ name: toolCall.name,
149
+ args: toolCall.args
150
+ };
151
+ if (!removeId) {
152
+ functionCall.id = toolCall.id;
153
+ }
145
154
  return {
146
- functionCall: {
147
- name: toolCall.name,
148
- args: toolCall.args,
149
- id: toolCall.id
150
- },
155
+ functionCall,
151
156
  ...thoughtData
152
157
  };
153
158
  })
154
159
  };
155
160
  }
156
161
  const finalMessage = message;
162
+ const functionResponse = {
163
+ name: message.name,
164
+ response: parseJsonArgs(message.content)
165
+ };
166
+ if (!removeId) {
167
+ functionResponse.id = finalMessage.tool_call_id;
168
+ }
157
169
  return {
158
170
  role: "user",
159
171
  parts: [
160
172
  {
161
- functionResponse: {
162
- name: message.name,
163
- id: finalMessage.tool_call_id,
164
- response: parseJsonArgs(message.content)
165
- }
173
+ functionResponse
166
174
  }
167
175
  ]
168
176
  };
@@ -350,7 +358,7 @@ function prepareModelConfig(params, pluginConfig) {
350
358
  }
351
359
  let imageGeneration = pluginConfig.imageGeneration ?? false;
352
360
  if (imageGeneration) {
353
- imageGeneration = params.model.includes("gemini-2.0-flash-exp") || params.model.includes("gemini-2.5-flash-image");
361
+ imageGeneration = params.model.includes("gemini-2.0-flash-exp") || params.model.includes("image");
354
362
  }
355
363
  return {
356
364
  model,
@@ -394,13 +402,13 @@ function createGenerationConfig(params, modelConfig, pluginConfig) {
394
402
  maxOutputTokens: params.model.includes("vision") ? void 0 : params.maxTokens,
395
403
  topP: params.topP,
396
404
  responseModalities: modelConfig.imageGeneration ? ["TEXT", "IMAGE"] : void 0,
397
- thinkingConfig: modelConfig.enabledThinking != null || pluginConfig.includeThoughts ? (0, import_koishi.filterKeys)(
405
+ thinkingConfig: modelConfig.enabledThinking != null || pluginConfig.includeThoughts ? filterKeys(
398
406
  {
399
407
  thinkingBudget: modelConfig.thinkingBudget,
400
408
  thinkingLevel: modelConfig.thinkingLevel,
401
409
  includeThoughts: pluginConfig.includeThoughts
402
410
  },
403
- (k, v) => v != null
411
+ notNullFn
404
412
  ) : void 0
405
413
  };
406
414
  }
@@ -434,6 +442,16 @@ function isChatResponse(response) {
434
442
  return "candidates" in response;
435
443
  }
436
444
  __name(isChatResponse, "isChatResponse");
445
+ function notNullFn(_, v) {
446
+ return v != null;
447
+ }
448
+ __name(notNullFn, "notNullFn");
449
+ function filterKeys(obj, fn) {
450
+ return Object.fromEntries(
451
+ Object.entries(obj).filter(([k, v]) => fn(k, v))
452
+ );
453
+ }
454
+ __name(filterKeys, "filterKeys");
437
455
 
438
456
  // src/requester.ts
439
457
  var import_string2 = require("koishi-plugin-chatluna/utils/string");
@@ -1096,33 +1114,33 @@ function apply(ctx, config) {
1096
1114
  });
1097
1115
  }
1098
1116
  __name(apply, "apply");
1099
- var Config4 = import_koishi2.Schema.intersect([
1117
+ var Config4 = import_koishi.Schema.intersect([
1100
1118
  import_chat.ChatLunaPlugin.Config,
1101
- import_koishi2.Schema.object({
1102
- platform: import_koishi2.Schema.string().default("gemini"),
1103
- apiKeys: import_koishi2.Schema.array(
1104
- import_koishi2.Schema.tuple([
1105
- import_koishi2.Schema.string().role("secret").default(""),
1106
- import_koishi2.Schema.string().default(
1119
+ import_koishi.Schema.object({
1120
+ platform: import_koishi.Schema.string().default("gemini"),
1121
+ apiKeys: import_koishi.Schema.array(
1122
+ import_koishi.Schema.tuple([
1123
+ import_koishi.Schema.string().role("secret").default(""),
1124
+ import_koishi.Schema.string().default(
1107
1125
  "https://generativelanguage.googleapis.com/v1beta"
1108
1126
  ),
1109
- import_koishi2.Schema.boolean().default(true)
1127
+ import_koishi.Schema.boolean().default(true)
1110
1128
  ])
1111
1129
  ).default([[]]).role("table")
1112
1130
  }),
1113
- import_koishi2.Schema.object({
1114
- maxContextRatio: import_koishi2.Schema.number().min(0).max(1).step(1e-4).role("slider").default(0.35),
1115
- temperature: import_koishi2.Schema.percent().min(0).max(2).step(0.1).default(1),
1116
- googleSearch: import_koishi2.Schema.boolean().default(false),
1117
- codeExecution: import_koishi2.Schema.boolean().default(false),
1118
- urlContext: import_koishi2.Schema.boolean().default(false),
1119
- thinkingBudget: import_koishi2.Schema.number().min(-1).max(24576).default(-1),
1120
- includeThoughts: import_koishi2.Schema.boolean().default(false),
1121
- nonStreaming: import_koishi2.Schema.boolean().default(false),
1122
- imageGeneration: import_koishi2.Schema.boolean().default(false),
1123
- groundingContentDisplay: import_koishi2.Schema.boolean().default(false),
1124
- searchThreshold: import_koishi2.Schema.number().min(0).max(1).step(0.1).default(0.5),
1125
- useCamelCaseSystemInstruction: import_koishi2.Schema.boolean().default(false)
1131
+ import_koishi.Schema.object({
1132
+ maxContextRatio: import_koishi.Schema.number().min(0).max(1).step(1e-4).role("slider").default(0.35),
1133
+ temperature: import_koishi.Schema.percent().min(0).max(2).step(0.1).default(1),
1134
+ googleSearch: import_koishi.Schema.boolean().default(false),
1135
+ codeExecution: import_koishi.Schema.boolean().default(false),
1136
+ urlContext: import_koishi.Schema.boolean().default(false),
1137
+ thinkingBudget: import_koishi.Schema.number().min(-1).max(24576).default(-1),
1138
+ includeThoughts: import_koishi.Schema.boolean().default(false),
1139
+ nonStreaming: import_koishi.Schema.boolean().default(false),
1140
+ imageGeneration: import_koishi.Schema.boolean().default(false),
1141
+ groundingContentDisplay: import_koishi.Schema.boolean().default(false),
1142
+ searchThreshold: import_koishi.Schema.number().min(0).max(1).step(0.1).default(0.5),
1143
+ useCamelCaseSystemInstruction: import_koishi.Schema.boolean().default(false)
1126
1144
  })
1127
1145
  ]).i18n({
1128
1146
  "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-2.0-flash-exp` 和 `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" }] };
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-2.0-flash-exp` 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" }] };
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,16 @@ 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 { filterKeys } from "koishi";
68
67
  async function langchainMessageToGeminiMessage(messages, plugin, model) {
69
68
  return Promise.all(
70
69
  messages.map(async (message) => {
71
70
  const role = messageTypeToGeminiRole(message.getType());
72
71
  const hasFunctionCall = message.tool_calls != null && message.tool_calls.length > 0;
73
72
  if (role === "function" || hasFunctionCall) {
74
- return processFunctionMessage(message);
73
+ return processFunctionMessage(
74
+ message,
75
+ plugin.config.useCamelCaseSystemInstruction
76
+ );
75
77
  }
76
78
  const result = {
77
79
  role,
@@ -131,7 +133,7 @@ function parseJsonArgs(args) {
131
133
  }
132
134
  }
133
135
  __name(parseJsonArgs, "parseJsonArgs");
134
- function processFunctionMessage(message) {
136
+ function processFunctionMessage(message, removeId) {
135
137
  const thoughtData = message.additional_kwargs["thought_data"] ?? {};
136
138
  if (message["tool_calls"]) {
137
139
  message = message;
@@ -139,27 +141,33 @@ function processFunctionMessage(message) {
139
141
  return {
140
142
  role: "model",
141
143
  parts: toolCalls.map((toolCall) => {
144
+ const functionCall = {
145
+ name: toolCall.name,
146
+ args: toolCall.args
147
+ };
148
+ if (!removeId) {
149
+ functionCall.id = toolCall.id;
150
+ }
142
151
  return {
143
- functionCall: {
144
- name: toolCall.name,
145
- args: toolCall.args,
146
- id: toolCall.id
147
- },
152
+ functionCall,
148
153
  ...thoughtData
149
154
  };
150
155
  })
151
156
  };
152
157
  }
153
158
  const finalMessage = message;
159
+ const functionResponse = {
160
+ name: message.name,
161
+ response: parseJsonArgs(message.content)
162
+ };
163
+ if (!removeId) {
164
+ functionResponse.id = finalMessage.tool_call_id;
165
+ }
154
166
  return {
155
167
  role: "user",
156
168
  parts: [
157
169
  {
158
- functionResponse: {
159
- name: message.name,
160
- id: finalMessage.tool_call_id,
161
- response: parseJsonArgs(message.content)
162
- }
170
+ functionResponse
163
171
  }
164
172
  ]
165
173
  };
@@ -347,7 +355,7 @@ function prepareModelConfig(params, pluginConfig) {
347
355
  }
348
356
  let imageGeneration = pluginConfig.imageGeneration ?? false;
349
357
  if (imageGeneration) {
350
- imageGeneration = params.model.includes("gemini-2.0-flash-exp") || params.model.includes("gemini-2.5-flash-image");
358
+ imageGeneration = params.model.includes("gemini-2.0-flash-exp") || params.model.includes("image");
351
359
  }
352
360
  return {
353
361
  model,
@@ -397,7 +405,7 @@ function createGenerationConfig(params, modelConfig, pluginConfig) {
397
405
  thinkingLevel: modelConfig.thinkingLevel,
398
406
  includeThoughts: pluginConfig.includeThoughts
399
407
  },
400
- (k, v) => v != null
408
+ notNullFn
401
409
  ) : void 0
402
410
  };
403
411
  }
@@ -431,6 +439,16 @@ function isChatResponse(response) {
431
439
  return "candidates" in response;
432
440
  }
433
441
  __name(isChatResponse, "isChatResponse");
442
+ function notNullFn(_, v) {
443
+ return v != null;
444
+ }
445
+ __name(notNullFn, "notNullFn");
446
+ function filterKeys(obj, fn) {
447
+ return Object.fromEntries(
448
+ Object.entries(obj).filter(([k, v]) => fn(k, v))
449
+ );
450
+ }
451
+ __name(filterKeys, "filterKeys");
434
452
 
435
453
  // src/requester.ts
436
454
  import { getMessageContent } from "koishi-plugin-chatluna/utils/string";
@@ -6,9 +6,9 @@ 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
- constructor(ctx: Context, _configPool: ClientConfigPool<ClientConfig>, _pluginConfig: Config, _plugin: ChatLunaPlugin);
11
+ constructor(ctx: Context, _configPool: ClientConfigPool<ClientConfig>, _pluginConfig: Config, _plugin: ChatLunaPlugin<ClientConfig, Config>);
12
12
  completion(params: ModelRequestParams): Promise<ChatGeneration>;
13
13
  completionStreamInternal(params: ModelRequestParams): AsyncGenerator<ChatGenerationChunk>;
14
14
  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
- export declare function langchainMessageToGeminiMessage(messages: BaseMessage[], plugin: ChatLunaPlugin, model?: string): Promise<ChatCompletionResponseMessage[]>;
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;
@@ -28,20 +29,20 @@ export declare function createGenerationConfig(params: ModelRequestParams, model
28
29
  maxOutputTokens: number;
29
30
  topP: number;
30
31
  responseModalities: string[];
31
- thinkingConfig: import("cosmokit").Dict<string | number | boolean, "thinkingBudget" | "thinkingLevel" | "includeThoughts">;
32
+ thinkingConfig: Record<"thinkingBudget" | "includeThoughts" | "thinkingLevel", string | number | boolean>;
32
33
  };
33
- export declare function createChatGenerationParams(params: ModelRequestParams, plugin: ChatLunaPlugin, modelConfig: ReturnType<typeof prepareModelConfig>, pluginConfig: Config): Promise<{
34
- [x: string]: {
34
+ export declare function createChatGenerationParams(params: ModelRequestParams, plugin: ChatLunaPlugin<ClientConfig, Config>, modelConfig: ReturnType<typeof prepareModelConfig>, pluginConfig: Config): Promise<{
35
+ [x: string]: Record<string, any> | ChatCompletionResponseMessage | ChatCompletionResponseMessage[] | {
36
+ category: string;
37
+ threshold: string;
38
+ }[] | {
35
39
  stopSequences: string | string[];
36
40
  temperature: number;
37
41
  maxOutputTokens: number;
38
42
  topP: number;
39
43
  responseModalities: string[];
40
- thinkingConfig: import("cosmokit").Dict<string | number | boolean, "thinkingBudget" | "thinkingLevel" | "includeThoughts">;
41
- } | ChatCompletionResponseMessage | ChatCompletionResponseMessage[] | {
42
- category: string;
43
- threshold: string;
44
- }[] | Record<string, any>;
44
+ thinkingConfig: Record<"thinkingBudget" | "includeThoughts" | "thinkingLevel", string | number | boolean>;
45
+ };
45
46
  contents: ChatCompletionResponseMessage[];
46
47
  safetySettings: {
47
48
  category: string;
@@ -53,7 +54,7 @@ export declare function createChatGenerationParams(params: ModelRequestParams, p
53
54
  maxOutputTokens: number;
54
55
  topP: number;
55
56
  responseModalities: string[];
56
- thinkingConfig: import("cosmokit").Dict<string | number | boolean, "thinkingBudget" | "thinkingLevel" | "includeThoughts">;
57
+ thinkingConfig: Record<"thinkingBudget" | "includeThoughts" | "thinkingLevel", string | number | boolean>;
57
58
  };
58
59
  tools: Record<string, any>;
59
60
  }>;
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.7",
4
+ "version": "1.3.9",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "lib/index.mjs",
7
7
  "typings": "lib/index.d.ts",