koishi-plugin-chatluna-google-gemini-adapter 1.0.0-beta.26 → 1.0.0-beta.28

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 CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  ## [![npm](https://img.shields.io/npm/v/koishi-plugin-chatluna-google-gemini-adapter)](https://www.npmjs.com/package/koishi-plugin-chatluna-google-gemini) [![npm](https://img.shields.io/npm/dm/koishi-plugin-chatluna-google-gemini-adapter)](https://www.npmjs.com/package//koishi-plugin-chatluna-google-gemini-adapter)
4
4
 
5
- > 为 ChatLuna 提供 Google-gemini 支持的适配器
5
+ > 为 ChatLuna 提供 Google Gemini 支持的适配器
6
6
 
7
- [Google-gemini 适配器文档](https://chatluna.chat/guide/configure-model-platform/google-gemini.html)
7
+ [Gemini 适配器文档](https://chatluna.chat/guide/configure-model-platform/google-gemini.html)
package/lib/index.cjs CHANGED
@@ -23,21 +23,21 @@ 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: "请求选项", apiKeys: { $inner: ["Gemini 的 API Key", "Gemini API 的请求地址"], $desc: "Gemini 的 API Key 和请求地址列表。" } }, { $desc: "模型配置", maxTokens: "回复的最大 Token 数(16~2097000,必须是 16 的倍数)。注意:仅当您使用的模型最大 Token 为 8000 及以上时,才建议设置超过 2000 token。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。" }] };
26
+ module2.exports = { $inner: [{}, { $desc: "请求选项", 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: "为模型启用谷歌搜索。", searchThreshold: "搜索的置信度阈值,范围:0~1,设置的数值越低,则越倾向于使用谷歌搜索。" }] };
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", 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" }] };
33
+ module2.exports = { $inner: [{}, { $desc: "API Configuration", 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", 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" }] };
34
34
  }
35
35
  });
36
36
 
37
37
  // src/index.ts
38
38
  var src_exports = {};
39
39
  __export(src_exports, {
40
- Config: () => Config,
40
+ Config: () => Config3,
41
41
  apply: () => apply,
42
42
  inject: () => inject,
43
43
  logger: () => logger,
@@ -132,7 +132,7 @@ async function langchainMessageToGeminiMessage(messages, model) {
132
132
  }
133
133
  ]
134
134
  };
135
- if ((model.includes("vision") || model.includes("gemini-1.5")) && images != null) {
135
+ if ((model.includes("vision") || model.includes("gemini")) && images != null && !model.includes("gemini-1.0")) {
136
136
  for (const image of images) {
137
137
  result2.parts.push({
138
138
  inline_data: {
@@ -157,15 +157,26 @@ async function langchainMessageToGeminiMessage(messages, model) {
157
157
  role: "user",
158
158
  parts: message.parts
159
159
  });
160
- if (mappedMessage?.[i + 1]?.role === "model") {
160
+ const nextMessage = mappedMessage?.[i + 1];
161
+ if (nextMessage?.role === "model") {
161
162
  continue;
162
163
  }
163
- if (mappedMessage?.[i + 1]?.role === "user") {
164
+ if (nextMessage?.role === "user" || nextMessage?.role === "system") {
164
165
  result.push({
165
166
  role: "model",
166
167
  parts: [{ text: "Okay, what do I need to do?" }]
167
168
  });
168
169
  }
170
+ if (nextMessage?.role === "system") {
171
+ result.push({
172
+ role: "user",
173
+ parts: [
174
+ {
175
+ text: "Continue what I said to you last message. Follow these instructions."
176
+ }
177
+ ]
178
+ });
179
+ }
169
180
  }
170
181
  if (result[result.length - 1].role === "model") {
171
182
  result.push({
@@ -226,11 +237,38 @@ function partAsType(part) {
226
237
  return part;
227
238
  }
228
239
  __name(partAsType, "partAsType");
229
- function formatToolsToGeminiAITools(tools) {
230
- if (tools.length < 1) {
240
+ function formatToolsToGeminiAITools(tools, config, model) {
241
+ if (tools.length < 1 && !config.googleSearch) {
231
242
  return void 0;
232
243
  }
233
- return tools.map(formatToolToGeminiAITool);
244
+ const functions = tools.map(formatToolToGeminiAITool);
245
+ const result = [];
246
+ if (functions.length > 0 && !config.googleSearch) {
247
+ result.push({
248
+ functionDeclarations: functions
249
+ });
250
+ } else if (functions.length > 0 && config.googleSearch) {
251
+ logger.warn(
252
+ "Google search is enabled, function calls will be disabled."
253
+ );
254
+ }
255
+ if (config.googleSearch) {
256
+ if (model.includes("gemini-2")) {
257
+ result.push({
258
+ google_search: {}
259
+ });
260
+ } else {
261
+ result.push({
262
+ google_search_retrieval: {
263
+ dynamic_retrieval_config: {
264
+ mode: "MODE_DYNAMIC",
265
+ dynamic_threshold: config.searchThreshold
266
+ }
267
+ }
268
+ });
269
+ }
270
+ }
271
+ return result;
234
272
  }
235
273
  __name(formatToolsToGeminiAITools, "formatToolsToGeminiAITools");
236
274
  function formatToolToGeminiAITool(tool) {
@@ -263,10 +301,11 @@ __name(messageTypeToGeminiRole, "messageTypeToGeminiRole");
263
301
 
264
302
  // src/requester.ts
265
303
  var GeminiRequester = class extends import_api.ModelRequester {
266
- constructor(_config, _plugin) {
304
+ constructor(_config, _plugin, _pluginConfig) {
267
305
  super();
268
306
  this._config = _config;
269
307
  this._plugin = _plugin;
308
+ this._pluginConfig = _pluginConfig;
270
309
  }
271
310
  static {
272
311
  __name(this, "GeminiRequester");
@@ -304,9 +343,11 @@ var GeminiRequester = class extends import_api.ModelRequester {
304
343
  maxOutputTokens: params.model.includes("vision") ? void 0 : params.maxTokens,
305
344
  topP: params.topP
306
345
  },
307
- tools: !params.model.includes("vision") && params.tools != null ? {
308
- functionDeclarations: formatToolsToGeminiAITools(params.tools)
309
- } : void 0
346
+ tools: params.tools != null || this._pluginConfig.googleSearch ? formatToolsToGeminiAITools(
347
+ params.tools ?? [],
348
+ this._pluginConfig,
349
+ params.model
350
+ ) : void 0
310
351
  },
311
352
  {
312
353
  signal: params.signal
@@ -494,7 +535,6 @@ var GeminiRequester = class extends import_api.ModelRequester {
494
535
  }
495
536
  }
496
537
  const body = JSON.stringify(data);
497
- console.log(body);
498
538
  return this._plugin.fetch(requestUrl, {
499
539
  body,
500
540
  headers: this._buildHeaders(),
@@ -533,7 +573,11 @@ var GeminiClient = class extends import_client.PlatformModelAndEmbeddingsClient
533
573
  constructor(ctx, _config, clientConfig, plugin) {
534
574
  super(ctx, clientConfig);
535
575
  this._config = _config;
536
- this._requester = new GeminiRequester(clientConfig, plugin);
576
+ this._requester = new GeminiRequester(
577
+ clientConfig,
578
+ plugin,
579
+ this._config
580
+ );
537
581
  }
538
582
  static {
539
583
  __name(this, "GeminiClient");
@@ -641,7 +685,7 @@ function apply(ctx, config) {
641
685
  });
642
686
  }
643
687
  __name(apply, "apply");
644
- var Config = import_koishi.Schema.intersect([
688
+ var Config3 = import_koishi.Schema.intersect([
645
689
  import_chat.ChatLunaPlugin.Config,
646
690
  import_koishi.Schema.object({
647
691
  apiKeys: import_koishi.Schema.array(
@@ -655,7 +699,9 @@ var Config = import_koishi.Schema.intersect([
655
699
  }),
656
700
  import_koishi.Schema.object({
657
701
  maxTokens: import_koishi.Schema.number().min(16).max(2097e3).step(16).default(8064),
658
- temperature: import_koishi.Schema.percent().min(0).max(2).step(0.1).default(0.8)
702
+ temperature: import_koishi.Schema.percent().min(0).max(2).step(0.1).default(0.8),
703
+ googleSearch: import_koishi.Schema.boolean().default(false),
704
+ searchThreshold: import_koishi.Schema.number().min(0).max(1).step(0.1).default(0.5)
659
705
  })
660
706
  ]).i18n({
661
707
  "zh-CN": require_zh_CN_schema(),
package/lib/index.d.ts CHANGED
@@ -14,6 +14,8 @@ export interface Config extends ChatLunaPlugin.Config {
14
14
  apiKeys: [string, string][];
15
15
  maxTokens: number;
16
16
  temperature: number;
17
+ googleSearch: boolean;
18
+ searchThreshold: number;
17
19
  }
18
20
  export const Config: Schema<Config>;
19
21
  export const inject: string[];
@@ -80,14 +82,15 @@ export interface CreateEmbeddingResponse {
80
82
  export type ChatCompletionResponseMessageRoleEnum = 'system' | 'model' | 'user' | 'function';
81
83
  export function langchainMessageToGeminiMessage(messages: BaseMessage[], model?: string): Promise<ChatCompletionResponseMessage[]>;
82
84
  export function partAsType<T extends ChatPart>(part: ChatPart): T;
83
- export function formatToolsToGeminiAITools(tools: StructuredTool[]): ChatCompletionFunction[];
85
+ export function formatToolsToGeminiAITools(tools: StructuredTool[], config: Config, model: string): Record<string, any>;
84
86
  export function formatToolToGeminiAITool(tool: StructuredTool): ChatCompletionFunction;
85
87
  export function messageTypeToGeminiRole(type: MessageType): ChatCompletionResponseMessageRoleEnum;
86
88
  export function convertDeltaToMessageChunk(delta: Record<string, any>, defaultRole?: ChatCompletionResponseMessageRoleEnum): HumanMessageChunk | AIMessageChunk | SystemMessageChunk | ChatMessageChunk;
87
89
  export class GeminiRequester extends ModelRequester implements EmbeddingsRequester {
88
90
  private _config;
89
91
  private _plugin;
90
- constructor(_config: ClientConfig, _plugin: ChatLunaPlugin);
92
+ private _pluginConfig;
93
+ constructor(_config: ClientConfig, _plugin: ChatLunaPlugin, _pluginConfig: Config);
91
94
  completionStream(params: ModelRequestParams): AsyncGenerator<ChatGenerationChunk>;
92
95
  embeddings(params: EmbeddingsRequestParams): Promise<number[] | number[][]>;
93
96
  getModels(): Promise<string[]>;
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: "请求选项", apiKeys: { $inner: ["Gemini 的 API Key", "Gemini API 的请求地址"], $desc: "Gemini 的 API Key 和请求地址列表。" } }, { $desc: "模型配置", maxTokens: "回复的最大 Token 数(16~2097000,必须是 16 的倍数)。注意:仅当您使用的模型最大 Token 为 8000 及以上时,才建议设置超过 2000 token。", temperature: "回复的随机性程度,数值越高,回复越随机(范围:0~2)。" }] };
11
+ module.exports = { $inner: [{}, { $desc: "请求选项", 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: "为模型启用谷歌搜索。", searchThreshold: "搜索的置信度阈值,范围:0~1,设置的数值越低,则越倾向于使用谷歌搜索。" }] };
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", 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" }] };
18
+ module.exports = { $inner: [{}, { $desc: "API Configuration", 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", 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" }] };
19
19
  }
20
20
  });
21
21
 
@@ -126,7 +126,7 @@ async function langchainMessageToGeminiMessage(messages, model) {
126
126
  }
127
127
  ]
128
128
  };
129
- if ((model.includes("vision") || model.includes("gemini-1.5")) && images != null) {
129
+ if ((model.includes("vision") || model.includes("gemini")) && images != null && !model.includes("gemini-1.0")) {
130
130
  for (const image of images) {
131
131
  result2.parts.push({
132
132
  inline_data: {
@@ -151,15 +151,26 @@ async function langchainMessageToGeminiMessage(messages, model) {
151
151
  role: "user",
152
152
  parts: message.parts
153
153
  });
154
- if (mappedMessage?.[i + 1]?.role === "model") {
154
+ const nextMessage = mappedMessage?.[i + 1];
155
+ if (nextMessage?.role === "model") {
155
156
  continue;
156
157
  }
157
- if (mappedMessage?.[i + 1]?.role === "user") {
158
+ if (nextMessage?.role === "user" || nextMessage?.role === "system") {
158
159
  result.push({
159
160
  role: "model",
160
161
  parts: [{ text: "Okay, what do I need to do?" }]
161
162
  });
162
163
  }
164
+ if (nextMessage?.role === "system") {
165
+ result.push({
166
+ role: "user",
167
+ parts: [
168
+ {
169
+ text: "Continue what I said to you last message. Follow these instructions."
170
+ }
171
+ ]
172
+ });
173
+ }
163
174
  }
164
175
  if (result[result.length - 1].role === "model") {
165
176
  result.push({
@@ -220,11 +231,38 @@ function partAsType(part) {
220
231
  return part;
221
232
  }
222
233
  __name(partAsType, "partAsType");
223
- function formatToolsToGeminiAITools(tools) {
224
- if (tools.length < 1) {
234
+ function formatToolsToGeminiAITools(tools, config, model) {
235
+ if (tools.length < 1 && !config.googleSearch) {
225
236
  return void 0;
226
237
  }
227
- return tools.map(formatToolToGeminiAITool);
238
+ const functions = tools.map(formatToolToGeminiAITool);
239
+ const result = [];
240
+ if (functions.length > 0 && !config.googleSearch) {
241
+ result.push({
242
+ functionDeclarations: functions
243
+ });
244
+ } else if (functions.length > 0 && config.googleSearch) {
245
+ logger.warn(
246
+ "Google search is enabled, function calls will be disabled."
247
+ );
248
+ }
249
+ if (config.googleSearch) {
250
+ if (model.includes("gemini-2")) {
251
+ result.push({
252
+ google_search: {}
253
+ });
254
+ } else {
255
+ result.push({
256
+ google_search_retrieval: {
257
+ dynamic_retrieval_config: {
258
+ mode: "MODE_DYNAMIC",
259
+ dynamic_threshold: config.searchThreshold
260
+ }
261
+ }
262
+ });
263
+ }
264
+ }
265
+ return result;
228
266
  }
229
267
  __name(formatToolsToGeminiAITools, "formatToolsToGeminiAITools");
230
268
  function formatToolToGeminiAITool(tool) {
@@ -257,10 +295,11 @@ __name(messageTypeToGeminiRole, "messageTypeToGeminiRole");
257
295
 
258
296
  // src/requester.ts
259
297
  var GeminiRequester = class extends ModelRequester {
260
- constructor(_config, _plugin) {
298
+ constructor(_config, _plugin, _pluginConfig) {
261
299
  super();
262
300
  this._config = _config;
263
301
  this._plugin = _plugin;
302
+ this._pluginConfig = _pluginConfig;
264
303
  }
265
304
  static {
266
305
  __name(this, "GeminiRequester");
@@ -298,9 +337,11 @@ var GeminiRequester = class extends ModelRequester {
298
337
  maxOutputTokens: params.model.includes("vision") ? void 0 : params.maxTokens,
299
338
  topP: params.topP
300
339
  },
301
- tools: !params.model.includes("vision") && params.tools != null ? {
302
- functionDeclarations: formatToolsToGeminiAITools(params.tools)
303
- } : void 0
340
+ tools: params.tools != null || this._pluginConfig.googleSearch ? formatToolsToGeminiAITools(
341
+ params.tools ?? [],
342
+ this._pluginConfig,
343
+ params.model
344
+ ) : void 0
304
345
  },
305
346
  {
306
347
  signal: params.signal
@@ -488,7 +529,6 @@ var GeminiRequester = class extends ModelRequester {
488
529
  }
489
530
  }
490
531
  const body = JSON.stringify(data);
491
- console.log(body);
492
532
  return this._plugin.fetch(requestUrl, {
493
533
  body,
494
534
  headers: this._buildHeaders(),
@@ -527,7 +567,11 @@ var GeminiClient = class extends PlatformModelAndEmbeddingsClient {
527
567
  constructor(ctx, _config, clientConfig, plugin) {
528
568
  super(ctx, clientConfig);
529
569
  this._config = _config;
530
- this._requester = new GeminiRequester(clientConfig, plugin);
570
+ this._requester = new GeminiRequester(
571
+ clientConfig,
572
+ plugin,
573
+ this._config
574
+ );
531
575
  }
532
576
  static {
533
577
  __name(this, "GeminiClient");
@@ -635,7 +679,7 @@ function apply(ctx, config) {
635
679
  });
636
680
  }
637
681
  __name(apply, "apply");
638
- var Config = Schema.intersect([
682
+ var Config3 = Schema.intersect([
639
683
  ChatLunaPlugin.Config,
640
684
  Schema.object({
641
685
  apiKeys: Schema.array(
@@ -649,7 +693,9 @@ var Config = Schema.intersect([
649
693
  }),
650
694
  Schema.object({
651
695
  maxTokens: Schema.number().min(16).max(2097e3).step(16).default(8064),
652
- temperature: Schema.percent().min(0).max(2).step(0.1).default(0.8)
696
+ temperature: Schema.percent().min(0).max(2).step(0.1).default(0.8),
697
+ googleSearch: Schema.boolean().default(false),
698
+ searchThreshold: Schema.number().min(0).max(1).step(0.1).default(0.5)
653
699
  })
654
700
  ]).i18n({
655
701
  "zh-CN": require_zh_CN_schema(),
@@ -659,7 +705,7 @@ var Config = Schema.intersect([
659
705
  var inject = ["chatluna"];
660
706
  var name = "chatluna-google-gemini-adapter";
661
707
  export {
662
- Config,
708
+ Config3 as Config,
663
709
  apply,
664
710
  inject,
665
711
  logger,
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.0.0-beta.26",
4
+ "version": "1.0.0-beta.28",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "lib/index.mjs",
7
7
  "typings": "lib/index.d.ts",
@@ -33,16 +33,16 @@
33
33
  "build": "atsc -b"
34
34
  },
35
35
  "resolutions": {
36
- "@langchain/core": "0.3.11",
36
+ "@langchain/core": "0.3.18",
37
37
  "js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.15"
38
38
  },
39
39
  "overrides": {
40
- "@langchain/core": "0.3.11",
40
+ "@langchain/core": "0.3.18",
41
41
  "js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.15"
42
42
  },
43
43
  "pnpm": {
44
44
  "overrides": {
45
- "@langchain/core": "0.3.11",
45
+ "@langchain/core": "0.3.18",
46
46
  "js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.15"
47
47
  }
48
48
  },
@@ -62,18 +62,18 @@
62
62
  "adapter"
63
63
  ],
64
64
  "dependencies": {
65
- "@langchain/core": "^0.3.11",
65
+ "@langchain/core": "^0.3.18",
66
66
  "@streamparser/json": "^0.0.21",
67
- "zod": "^3.24.0-canary.20240701T200529",
68
- "zod-to-json-schema": "^3.23.3"
67
+ "zod": "^3.24.0-canary.20241107T043915",
68
+ "zod-to-json-schema": "^3.23.5"
69
69
  },
70
70
  "devDependencies": {
71
71
  "atsc": "^2.1.0",
72
- "koishi": "^4.18.0"
72
+ "koishi": "^4.18.1"
73
73
  },
74
74
  "peerDependencies": {
75
- "koishi": "^4.18.0",
76
- "koishi-plugin-chatluna": "^1.0.0-beta.103"
75
+ "koishi": "^4.18.1",
76
+ "koishi-plugin-chatluna": "^1.0.0-beta.131"
77
77
  },
78
78
  "koishi": {
79
79
  "description": {