koishi-plugin-chatluna-google-gemini-adapter 1.3.0-alpha.13 → 1.3.0-alpha.15

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 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 参数。" }] };
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 参数。" }] };
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)"], $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." }] };
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." }] };
34
34
  }
35
35
  });
36
36
 
@@ -685,6 +685,18 @@ var GeminiRequester = class extends import_api.ModelRequester {
685
685
  return;
686
686
  }
687
687
  const transformValue = typeof chunk === "string" ? JSON.parse(chunk) : chunk;
688
+ if (transformValue.usageMetadata) {
689
+ const promptTokens = transformValue.usageMetadata.promptTokenCount;
690
+ const totalTokens = transformValue.usageMetadata.totalTokenCount;
691
+ const completionTokens = transformValue.usageMetadata.candidatesTokenCount ?? totalTokens - promptTokens;
692
+ controller.enqueue({
693
+ usage: {
694
+ promptTokens,
695
+ completionTokens,
696
+ totalTokens
697
+ }
698
+ });
699
+ }
688
700
  if (!transformValue?.candidates) {
689
701
  return;
690
702
  }
@@ -723,6 +735,20 @@ var GeminiRequester = class extends import_api.ModelRequester {
723
735
  let errorCount = 0;
724
736
  let functionIndex = 0;
725
737
  for await (const chunk of iterable) {
738
+ let parsedChunk;
739
+ if (parsedChunk = partAsTypeCheck(
740
+ chunk,
741
+ (chunk2) => chunk2["usage"] != null
742
+ )) {
743
+ const generationChunk = new import_outputs.ChatGenerationChunk({
744
+ message: new import_messages.AIMessageChunk(""),
745
+ text: "",
746
+ generationInfo: {
747
+ tokenUsage: parsedChunk.usage
748
+ }
749
+ });
750
+ yield { type: "generation", generation: generationChunk };
751
+ }
726
752
  try {
727
753
  const { updatedContent, updatedReasoning, updatedToolCalling } = await this._processChunk(
728
754
  chunk,
@@ -998,11 +1024,13 @@ var import_logger2 = require("koishi-plugin-chatluna/utils/logger");
998
1024
  var logger;
999
1025
  var reusable = true;
1000
1026
  function apply(ctx, config) {
1001
- const plugin = new import_chat.ChatLunaPlugin(ctx, config, config.platform);
1002
1027
  logger = (0, import_logger2.createLogger)(ctx, "chatluna-gemini-adapter");
1003
1028
  ctx.on("ready", async () => {
1029
+ const plugin = new import_chat.ChatLunaPlugin(ctx, config, config.platform);
1004
1030
  plugin.parseConfig((config2) => {
1005
- return config2.apiKeys.map(([apiKey, apiEndpoint]) => {
1031
+ return config2.apiKeys.filter(([apiKey, _, enabled]) => {
1032
+ return apiKey.length > 0 && enabled;
1033
+ }).map(([apiKey, apiEndpoint]) => {
1006
1034
  return {
1007
1035
  apiKey,
1008
1036
  apiEndpoint,
@@ -1025,12 +1053,13 @@ var Config4 = import_koishi.Schema.intersect([
1025
1053
  platform: import_koishi.Schema.string().default("gemini"),
1026
1054
  apiKeys: import_koishi.Schema.array(
1027
1055
  import_koishi.Schema.tuple([
1028
- import_koishi.Schema.string().role("secret"),
1056
+ import_koishi.Schema.string().role("secret").required(true),
1029
1057
  import_koishi.Schema.string().default(
1030
1058
  "https://generativelanguage.googleapis.com/v1beta"
1031
- )
1059
+ ),
1060
+ import_koishi.Schema.boolean().default(true)
1032
1061
  ])
1033
- ).default([["", "https://generativelanguage.googleapis.com/v1beta"]])
1062
+ ).default([[]]).role("table")
1034
1063
  }),
1035
1064
  import_koishi.Schema.object({
1036
1065
  maxContextRatio: import_koishi.Schema.number().min(0).max(1).step(1e-4).role("slider").default(0.35),
package/lib/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export declare let logger: Logger;
4
4
  export declare const reusable = true;
5
5
  export declare function apply(ctx: Context, config: Config): void;
6
6
  export interface Config extends ChatLunaPlugin.Config {
7
- apiKeys: [string, string][];
7
+ apiKeys: [string, string, boolean][];
8
8
  maxContextRatio: number;
9
9
  platform: string;
10
10
  temperature: number;
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 参数。" }] };
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 参数。" }] };
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", 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." }] };
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." }] };
19
19
  }
20
20
  });
21
21
 
@@ -682,6 +682,18 @@ var GeminiRequester = class extends ModelRequester {
682
682
  return;
683
683
  }
684
684
  const transformValue = typeof chunk === "string" ? JSON.parse(chunk) : chunk;
685
+ if (transformValue.usageMetadata) {
686
+ const promptTokens = transformValue.usageMetadata.promptTokenCount;
687
+ const totalTokens = transformValue.usageMetadata.totalTokenCount;
688
+ const completionTokens = transformValue.usageMetadata.candidatesTokenCount ?? totalTokens - promptTokens;
689
+ controller.enqueue({
690
+ usage: {
691
+ promptTokens,
692
+ completionTokens,
693
+ totalTokens
694
+ }
695
+ });
696
+ }
685
697
  if (!transformValue?.candidates) {
686
698
  return;
687
699
  }
@@ -720,6 +732,20 @@ var GeminiRequester = class extends ModelRequester {
720
732
  let errorCount = 0;
721
733
  let functionIndex = 0;
722
734
  for await (const chunk of iterable) {
735
+ let parsedChunk;
736
+ if (parsedChunk = partAsTypeCheck(
737
+ chunk,
738
+ (chunk2) => chunk2["usage"] != null
739
+ )) {
740
+ const generationChunk = new ChatGenerationChunk({
741
+ message: new AIMessageChunk(""),
742
+ text: "",
743
+ generationInfo: {
744
+ tokenUsage: parsedChunk.usage
745
+ }
746
+ });
747
+ yield { type: "generation", generation: generationChunk };
748
+ }
723
749
  try {
724
750
  const { updatedContent, updatedReasoning, updatedToolCalling } = await this._processChunk(
725
751
  chunk,
@@ -995,11 +1021,13 @@ import { createLogger } from "koishi-plugin-chatluna/utils/logger";
995
1021
  var logger;
996
1022
  var reusable = true;
997
1023
  function apply(ctx, config) {
998
- const plugin = new ChatLunaPlugin(ctx, config, config.platform);
999
1024
  logger = createLogger(ctx, "chatluna-gemini-adapter");
1000
1025
  ctx.on("ready", async () => {
1026
+ const plugin = new ChatLunaPlugin(ctx, config, config.platform);
1001
1027
  plugin.parseConfig((config2) => {
1002
- return config2.apiKeys.map(([apiKey, apiEndpoint]) => {
1028
+ return config2.apiKeys.filter(([apiKey, _, enabled]) => {
1029
+ return apiKey.length > 0 && enabled;
1030
+ }).map(([apiKey, apiEndpoint]) => {
1003
1031
  return {
1004
1032
  apiKey,
1005
1033
  apiEndpoint,
@@ -1022,12 +1050,13 @@ var Config4 = Schema.intersect([
1022
1050
  platform: Schema.string().default("gemini"),
1023
1051
  apiKeys: Schema.array(
1024
1052
  Schema.tuple([
1025
- Schema.string().role("secret"),
1053
+ Schema.string().role("secret").required(true),
1026
1054
  Schema.string().default(
1027
1055
  "https://generativelanguage.googleapis.com/v1beta"
1028
- )
1056
+ ),
1057
+ Schema.boolean().default(true)
1029
1058
  ])
1030
- ).default([["", "https://generativelanguage.googleapis.com/v1beta"]])
1059
+ ).default([[]]).role("table")
1031
1060
  }),
1032
1061
  Schema.object({
1033
1062
  maxContextRatio: Schema.number().min(0).max(1).step(1e-4).role("slider").default(0.35),
package/lib/types.d.ts CHANGED
@@ -2,11 +2,18 @@ export interface ChatCompletionResponseMessage {
2
2
  role: string;
3
3
  parts?: ChatPart[];
4
4
  }
5
- export type ChatPart = ChatMessagePart | ChatInlineDataPart | ChatFunctionCallingPart | ChatFunctionResponsePart | ChatUploadDataPart;
5
+ export type ChatPart = ChatMessagePart | ChatInlineDataPart | ChatFunctionCallingPart | ChatFunctionResponsePart | ChatUploadDataPart | ChatUsageMetadataPart;
6
6
  export type ChatMessagePart = {
7
7
  text: string;
8
8
  thought?: boolean;
9
9
  };
10
+ export type ChatUsageMetadataPart = {
11
+ usage: {
12
+ promptTokens: number;
13
+ completionTokens: number;
14
+ totalTokens: number;
15
+ };
16
+ };
10
17
  export type ChatInlineDataPart = {
11
18
  inlineData: {
12
19
  mimeType: string;
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.0-alpha.13",
4
+ "version": "1.3.0-alpha.15",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "lib/index.mjs",
7
7
  "typings": "lib/index.d.ts",
@@ -62,7 +62,7 @@
62
62
  "adapter"
63
63
  ],
64
64
  "dependencies": {
65
- "@chatluna/v1-shared-adapter": "^1.0.11",
65
+ "@chatluna/v1-shared-adapter": "^1.0.13",
66
66
  "@langchain/core": "0.3.62",
67
67
  "zod": "3.25.76",
68
68
  "zod-to-json-schema": "^3.24.6"
@@ -73,7 +73,7 @@
73
73
  },
74
74
  "peerDependencies": {
75
75
  "koishi": "^4.18.9",
76
- "koishi-plugin-chatluna": "^1.3.0-alpha.49",
76
+ "koishi-plugin-chatluna": "^1.3.0-alpha.56",
77
77
  "koishi-plugin-chatluna-storage-service": "^0.0.9"
78
78
  },
79
79
  "peerDependenciesMeta": {