koishi-plugin-chatluna-google-gemini-adapter 1.3.0-alpha.1 → 1.3.0-alpha.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 CHANGED
@@ -5,6 +5,7 @@ import { ChatLunaBaseEmbeddings, ChatLunaChatModel } from 'koishi-plugin-chatlun
5
5
  import { ModelInfo } from 'koishi-plugin-chatluna/llm-core/platform/types';
6
6
  import { Config } from '.';
7
7
  import { ChatLunaPlugin } from 'koishi-plugin-chatluna/services/chat';
8
+ import { RunnableConfig } from '@langchain/core/runnables';
8
9
  export declare class GeminiClient extends PlatformModelAndEmbeddingsClient<ClientConfig> {
9
10
  private _config;
10
11
  plugin: ChatLunaPlugin;
@@ -12,6 +13,6 @@ export declare class GeminiClient extends PlatformModelAndEmbeddingsClient<Clien
12
13
  private _requester;
13
14
  get logger(): import("reggol");
14
15
  constructor(ctx: Context, _config: Config, plugin: ChatLunaPlugin);
15
- refreshModels(): Promise<ModelInfo[]>;
16
+ refreshModels(config?: RunnableConfig): Promise<ModelInfo[]>;
16
17
  protected _createModel(model: string): ChatLunaChatModel | ChatLunaBaseEmbeddings;
17
18
  }
package/lib/index.cjs CHANGED
@@ -51,7 +51,7 @@ var import_koishi = require("koishi");
51
51
  // src/client.ts
52
52
  var import_client = require("koishi-plugin-chatluna/llm-core/platform/client");
53
53
  var import_model = require("koishi-plugin-chatluna/llm-core/platform/model");
54
- var import_types = require("koishi-plugin-chatluna/llm-core/platform/types");
54
+ var import_types2 = require("koishi-plugin-chatluna/llm-core/platform/types");
55
55
  var import_error2 = require("koishi-plugin-chatluna/utils/error");
56
56
 
57
57
  // src/requester.ts
@@ -66,12 +66,12 @@ var import_stream = require("koishi-plugin-chatluna/utils/stream");
66
66
  var import_zod_to_json_schema = require("zod-to-json-schema");
67
67
  var import_v1_shared_adapter = require("@chatluna/v1-shared-adapter");
68
68
  var import_string = require("koishi-plugin-chatluna/utils/string");
69
- var import_zod = require("zod");
69
+ var import_types = require("@langchain/core/utils/types");
70
70
  async function langchainMessageToGeminiMessage(messages, plugin, model) {
71
71
  return Promise.all(
72
72
  messages.map(async (message) => {
73
73
  const role = messageTypeToGeminiRole(message.getType());
74
- const hasFunctionCall = message.additional_kwargs?.function_call != null;
74
+ const hasFunctionCall = message.tool_calls != null && message.tool_calls.length > 0;
75
75
  if (role === "function" || hasFunctionCall) {
76
76
  return processFunctionMessage(message);
77
77
  }
@@ -117,50 +117,43 @@ function extractSystemMessages(messages) {
117
117
  ];
118
118
  }
119
119
  __name(extractSystemMessages, "extractSystemMessages");
120
- function parseJsonSafely(content) {
121
- try {
122
- const result = JSON.parse(content);
123
- return typeof result === "string" ? { response: result } : result;
124
- } catch {
125
- return { response: content };
126
- }
127
- }
128
- __name(parseJsonSafely, "parseJsonSafely");
129
120
  function parseJsonArgs(args) {
130
121
  try {
131
122
  const result = JSON.parse(args);
132
- return typeof result === "string" ? { input: result } : result;
123
+ if (typeof result === "string") return { response: result };
124
+ if (Array.isArray(result)) return { response: result };
125
+ return result;
133
126
  } catch {
134
- return { input: args };
127
+ return { response: args };
135
128
  }
136
129
  }
137
130
  __name(parseJsonArgs, "parseJsonArgs");
138
131
  function processFunctionMessage(message) {
139
- const hasFunctionCall = message.additional_kwargs?.function_call != null;
140
- if (hasFunctionCall) {
141
- const functionCall = message.additional_kwargs.function_call;
132
+ if (message["tool_calls"]) {
133
+ message = message;
134
+ const toolCalls = message.tool_calls;
142
135
  return {
143
- role: "function",
144
- parts: [
145
- {
136
+ role: "model",
137
+ parts: toolCalls.map((toolCall) => {
138
+ return {
146
139
  functionCall: {
147
- name: functionCall.name,
148
- args: parseJsonArgs(functionCall.arguments)
140
+ name: toolCall.name,
141
+ args: toolCall.args,
142
+ id: toolCall.id
149
143
  }
150
- }
151
- ]
144
+ };
145
+ })
152
146
  };
153
147
  }
148
+ const finalMessage = message;
154
149
  return {
155
- role: "function",
150
+ role: "user",
156
151
  parts: [
157
152
  {
158
153
  functionResponse: {
159
154
  name: message.name,
160
- response: {
161
- name: message.name,
162
- content: parseJsonSafely(message.content)
163
- }
155
+ id: finalMessage.tool_call_id,
156
+ response: parseJsonArgs(message.content)
164
157
  }
165
158
  }
166
159
  ]
@@ -294,7 +287,7 @@ function formatToolsToGeminiAITools(tools, config, model) {
294
287
  __name(formatToolsToGeminiAITools, "formatToolsToGeminiAITools");
295
288
  function formatToolToGeminiAITool(tool) {
296
289
  const parameters = (0, import_v1_shared_adapter.removeAdditionalProperties)(
297
- tool.schema instanceof import_zod.ZodSchema ? (0, import_zod_to_json_schema.zodToJsonSchema)(tool.schema, {
290
+ (0, import_types.isZodSchemaV3)(tool.schema) ? (0, import_zod_to_json_schema.zodToJsonSchema)(tool.schema, {
298
291
  allowedAdditionalProperties: void 0
299
292
  }) : tool.schema
300
293
  );
@@ -314,7 +307,7 @@ function messageTypeToGeminiRole(type) {
314
307
  return "model";
315
308
  case "human":
316
309
  return "user";
317
- case "function":
310
+ case "tool":
318
311
  return "function";
319
312
  default:
320
313
  throw new Error(`Unknown message type: ${type}`);
@@ -326,7 +319,7 @@ function prepareModelConfig(params, pluginConfig) {
326
319
  let enabledThinking = null;
327
320
  if (model.includes("-thinking") && model.includes("gemini-2.5")) {
328
321
  enabledThinking = !model.includes("-non-thinking");
329
- model = model.replace("-nom-thinking", "").replace("-thinking", "");
322
+ model = model.replace("-non-thinking", "").replace("-thinking", "");
330
323
  }
331
324
  let thinkingBudget = pluginConfig.thinkingBudget ?? -1;
332
325
  if (!enabledThinking && !model.includes("2.5-pro")) {
@@ -529,12 +522,17 @@ var GeminiRequester = class extends import_api.ModelRequester {
529
522
  "error when calling gemini embeddings, Result: " + JSON.stringify(data)
530
523
  );
531
524
  }
532
- async getModels() {
525
+ async getModels(config) {
533
526
  try {
534
- const response = await this._get("models");
527
+ const response = await this._get("models", {
528
+ signal: config?.signal
529
+ });
535
530
  const data = await this._parseModelsResponse(response);
536
531
  return this._filterAndTransformModels(data.models);
537
532
  } catch (e) {
533
+ if (e instanceof import_error.ChatLunaError) {
534
+ throw e;
535
+ }
538
536
  const error = new Error(
539
537
  "error when listing gemini models, Error: " + e.message
540
538
  );
@@ -707,27 +705,23 @@ var GeminiRequester = class extends import_api.ModelRequester {
707
705
  async *_processChunks(iterable) {
708
706
  let reasoningContent = "";
709
707
  let errorCount = 0;
710
- const functionCall = {
711
- name: "",
712
- args: "",
713
- arguments: ""
714
- };
708
+ let functionIndex = 0;
715
709
  for await (const chunk of iterable) {
716
710
  try {
717
- const { updatedContent, updatedReasoning } = await this._processChunk(
711
+ const { updatedContent, updatedReasoning, updatedToolCalling } = await this._processChunk(
718
712
  chunk,
719
713
  reasoningContent,
720
- functionCall
714
+ functionIndex
721
715
  );
722
716
  if (updatedReasoning !== reasoningContent) {
723
717
  reasoningContent = updatedReasoning;
724
718
  yield { type: "reasoning", content: reasoningContent };
725
719
  continue;
726
720
  }
727
- if (updatedContent || functionCall.name) {
721
+ if (updatedContent || updatedToolCalling) {
728
722
  const messageChunk = this._createMessageChunk(
729
723
  updatedContent,
730
- functionCall,
724
+ updatedToolCalling,
731
725
  this.ctx.chatluna_storage != null ? void 0 : partAsTypeCheck(
732
726
  chunk,
733
727
  (part) => part["inlineData"] != null
@@ -739,6 +733,9 @@ var GeminiRequester = class extends import_api.ModelRequester {
739
733
  });
740
734
  yield { type: "generation", generation: generationChunk };
741
735
  }
736
+ if (updatedToolCalling) {
737
+ functionIndex++;
738
+ }
742
739
  } catch (e) {
743
740
  if (errorCount > 5) {
744
741
  logger.error("error with chunk", chunk);
@@ -753,7 +750,7 @@ var GeminiRequester = class extends import_api.ModelRequester {
753
750
  }
754
751
  }
755
752
  }
756
- async _processChunk(chunk, reasoningContent, functionCall) {
753
+ async _processChunk(chunk, reasoningContent, functionIndex) {
757
754
  const messagePart = partAsType(chunk);
758
755
  const chatFunctionCallingPart = partAsType(chunk);
759
756
  const imagePart = partAsTypeCheck(
@@ -790,30 +787,25 @@ var GeminiRequester = class extends import_api.ModelRequester {
790
787
  }
791
788
  }
792
789
  const deltaFunctionCall = chatFunctionCallingPart?.functionCall;
790
+ let updatedToolCalling;
793
791
  if (deltaFunctionCall) {
794
- this._updateFunctionCall(functionCall, deltaFunctionCall);
792
+ updatedToolCalling = this._createToolCallChunk(
793
+ deltaFunctionCall,
794
+ functionIndex
795
+ );
795
796
  }
796
797
  return {
797
798
  updatedContent: messageContent,
798
- updatedReasoning: reasoningContent
799
+ updatedReasoning: reasoningContent,
800
+ updatedToolCalling
799
801
  };
800
802
  }
801
- _updateFunctionCall(functionCall, deltaFunctionCall) {
802
- let args = deltaFunctionCall.args;
803
- try {
804
- let parsedArgs = JSON.parse(args);
805
- if (typeof parsedArgs !== "string") {
806
- args = parsedArgs;
807
- }
808
- parsedArgs = JSON.parse(args);
809
- if (typeof parsedArgs !== "string") {
810
- args = parsedArgs;
811
- }
812
- } catch (e) {
813
- }
814
- functionCall.args = JSON.stringify(args);
815
- functionCall.name = deltaFunctionCall.name;
816
- functionCall.arguments = deltaFunctionCall.args;
803
+ _createToolCallChunk(deltaFunctionCall, functionIndex) {
804
+ return {
805
+ name: deltaFunctionCall?.name,
806
+ args: JSON.stringify(deltaFunctionCall.args),
807
+ id: deltaFunctionCall.id ?? `function_call_${functionIndex}`
808
+ };
817
809
  }
818
810
  _handleFinalContent(reasoningContent, groundingContent) {
819
811
  if (reasoningContent.length > 0) {
@@ -836,15 +828,10 @@ ${groundingContent}`
836
828
  }
837
829
  _createMessageChunk(content, functionCall, imagePart) {
838
830
  const messageChunk = new import_messages.AIMessageChunk({
839
- content: content ?? ""
831
+ content: content ?? "",
832
+ tool_call_chunks: [functionCall].filter(Boolean)
840
833
  });
841
834
  messageChunk.additional_kwargs = {
842
- function_call: functionCall.name.length > 0 ? {
843
- name: functionCall.name,
844
- arguments: functionCall.args,
845
- args: functionCall.arguments
846
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
847
- } : void 0,
848
835
  images: imagePart ? [
849
836
  `data:${imagePart.inlineData.mimeType ?? "image/png"};base64,${imagePart.inlineData.data}`
850
837
  ] : void 0
@@ -867,11 +854,12 @@ ${groundingContent}`
867
854
  ...params
868
855
  });
869
856
  }
870
- _get(url) {
857
+ _get(url, params = {}) {
871
858
  const requestUrl = this._concatUrl(url);
872
859
  return this._plugin.fetch(requestUrl, {
873
860
  method: "GET",
874
- headers: this._buildHeaders()
861
+ headers: this._buildHeaders(),
862
+ ...params
875
863
  });
876
864
  }
877
865
  _concatUrl(url) {
@@ -919,9 +907,9 @@ var GeminiClient = class extends import_client.PlatformModelAndEmbeddingsClient
919
907
  get logger() {
920
908
  return logger;
921
909
  }
922
- async refreshModels() {
910
+ async refreshModels(config) {
923
911
  try {
924
- const rawModels = await this._requester.getModels();
912
+ const rawModels = await this._requester.getModels(config);
925
913
  if (!rawModels.length) {
926
914
  throw new import_error2.ChatLunaError(
927
915
  import_error2.ChatLunaErrorCode.MODEL_INIT_ERROR,
@@ -933,16 +921,16 @@ var GeminiClient = class extends import_client.PlatformModelAndEmbeddingsClient
933
921
  const info = {
934
922
  name: model.name,
935
923
  maxTokens: model.inputTokenLimit,
936
- type: model.name.includes("embedding") ? import_types.ModelType.embeddings : import_types.ModelType.llm,
924
+ type: model.name.includes("embedding") ? import_types2.ModelType.embeddings : import_types2.ModelType.llm,
937
925
  capabilities: [
938
- import_types.ModelCapabilities.ImageInput,
939
- import_types.ModelCapabilities.ToolCall
926
+ import_types2.ModelCapabilities.ImageInput,
927
+ import_types2.ModelCapabilities.ToolCall
940
928
  ]
941
929
  };
942
930
  if (model.name.includes("gemini-2.5") && !model.name.includes("pro") && !model.name.includes("image")) {
943
931
  if (!model.name.includes("-thinking")) {
944
932
  models.push(
945
- { ...info, name: model.name + "-nonthinking" },
933
+ { ...info, name: model.name + "-non-thinking" },
946
934
  { ...info, name: model.name + "-thinking" },
947
935
  info
948
936
  );
@@ -955,6 +943,9 @@ var GeminiClient = class extends import_client.PlatformModelAndEmbeddingsClient
955
943
  }
956
944
  return models;
957
945
  } catch (e) {
946
+ if (e instanceof import_error2.ChatLunaError) {
947
+ throw e;
948
+ }
958
949
  throw new import_error2.ChatLunaError(import_error2.ChatLunaErrorCode.MODEL_INIT_ERROR, e);
959
950
  }
960
951
  }
@@ -963,7 +954,7 @@ var GeminiClient = class extends import_client.PlatformModelAndEmbeddingsClient
963
954
  if (info == null) {
964
955
  throw new import_error2.ChatLunaError(import_error2.ChatLunaErrorCode.MODEL_NOT_FOUND);
965
956
  }
966
- if (info.type === import_types.ModelType.llm) {
957
+ if (info.type === import_types2.ModelType.llm) {
967
958
  return new import_model.ChatLunaChatModel({
968
959
  modelInfo: info,
969
960
  requester: this._requester,
@@ -992,8 +983,7 @@ function apply(ctx, config) {
992
983
  const plugin = new import_chat.ChatLunaPlugin(ctx, config, config.platform);
993
984
  logger = (0, import_logger.createLogger)(ctx, "chatluna-gemini-adapter");
994
985
  ctx.on("ready", async () => {
995
- plugin.registerToService();
996
- await plugin.parseConfig((config2) => {
986
+ plugin.parseConfig((config2) => {
997
987
  return config2.apiKeys.map(([apiKey, apiEndpoint]) => {
998
988
  return {
999
989
  apiKey,
package/lib/index.mjs CHANGED
@@ -63,12 +63,12 @@ import {
63
63
  isMessageContentImageUrl,
64
64
  isMessageContentText
65
65
  } from "koishi-plugin-chatluna/utils/string";
66
- import { ZodSchema } from "zod";
66
+ import { isZodSchemaV3 } from "@langchain/core/utils/types";
67
67
  async function langchainMessageToGeminiMessage(messages, plugin, model) {
68
68
  return Promise.all(
69
69
  messages.map(async (message) => {
70
70
  const role = messageTypeToGeminiRole(message.getType());
71
- const hasFunctionCall = message.additional_kwargs?.function_call != null;
71
+ const hasFunctionCall = message.tool_calls != null && message.tool_calls.length > 0;
72
72
  if (role === "function" || hasFunctionCall) {
73
73
  return processFunctionMessage(message);
74
74
  }
@@ -114,50 +114,43 @@ function extractSystemMessages(messages) {
114
114
  ];
115
115
  }
116
116
  __name(extractSystemMessages, "extractSystemMessages");
117
- function parseJsonSafely(content) {
118
- try {
119
- const result = JSON.parse(content);
120
- return typeof result === "string" ? { response: result } : result;
121
- } catch {
122
- return { response: content };
123
- }
124
- }
125
- __name(parseJsonSafely, "parseJsonSafely");
126
117
  function parseJsonArgs(args) {
127
118
  try {
128
119
  const result = JSON.parse(args);
129
- return typeof result === "string" ? { input: result } : result;
120
+ if (typeof result === "string") return { response: result };
121
+ if (Array.isArray(result)) return { response: result };
122
+ return result;
130
123
  } catch {
131
- return { input: args };
124
+ return { response: args };
132
125
  }
133
126
  }
134
127
  __name(parseJsonArgs, "parseJsonArgs");
135
128
  function processFunctionMessage(message) {
136
- const hasFunctionCall = message.additional_kwargs?.function_call != null;
137
- if (hasFunctionCall) {
138
- const functionCall = message.additional_kwargs.function_call;
129
+ if (message["tool_calls"]) {
130
+ message = message;
131
+ const toolCalls = message.tool_calls;
139
132
  return {
140
- role: "function",
141
- parts: [
142
- {
133
+ role: "model",
134
+ parts: toolCalls.map((toolCall) => {
135
+ return {
143
136
  functionCall: {
144
- name: functionCall.name,
145
- args: parseJsonArgs(functionCall.arguments)
137
+ name: toolCall.name,
138
+ args: toolCall.args,
139
+ id: toolCall.id
146
140
  }
147
- }
148
- ]
141
+ };
142
+ })
149
143
  };
150
144
  }
145
+ const finalMessage = message;
151
146
  return {
152
- role: "function",
147
+ role: "user",
153
148
  parts: [
154
149
  {
155
150
  functionResponse: {
156
151
  name: message.name,
157
- response: {
158
- name: message.name,
159
- content: parseJsonSafely(message.content)
160
- }
152
+ id: finalMessage.tool_call_id,
153
+ response: parseJsonArgs(message.content)
161
154
  }
162
155
  }
163
156
  ]
@@ -291,7 +284,7 @@ function formatToolsToGeminiAITools(tools, config, model) {
291
284
  __name(formatToolsToGeminiAITools, "formatToolsToGeminiAITools");
292
285
  function formatToolToGeminiAITool(tool) {
293
286
  const parameters = removeAdditionalProperties(
294
- tool.schema instanceof ZodSchema ? zodToJsonSchema(tool.schema, {
287
+ isZodSchemaV3(tool.schema) ? zodToJsonSchema(tool.schema, {
295
288
  allowedAdditionalProperties: void 0
296
289
  }) : tool.schema
297
290
  );
@@ -311,7 +304,7 @@ function messageTypeToGeminiRole(type) {
311
304
  return "model";
312
305
  case "human":
313
306
  return "user";
314
- case "function":
307
+ case "tool":
315
308
  return "function";
316
309
  default:
317
310
  throw new Error(`Unknown message type: ${type}`);
@@ -323,7 +316,7 @@ function prepareModelConfig(params, pluginConfig) {
323
316
  let enabledThinking = null;
324
317
  if (model.includes("-thinking") && model.includes("gemini-2.5")) {
325
318
  enabledThinking = !model.includes("-non-thinking");
326
- model = model.replace("-nom-thinking", "").replace("-thinking", "");
319
+ model = model.replace("-non-thinking", "").replace("-thinking", "");
327
320
  }
328
321
  let thinkingBudget = pluginConfig.thinkingBudget ?? -1;
329
322
  if (!enabledThinking && !model.includes("2.5-pro")) {
@@ -526,12 +519,17 @@ var GeminiRequester = class extends ModelRequester {
526
519
  "error when calling gemini embeddings, Result: " + JSON.stringify(data)
527
520
  );
528
521
  }
529
- async getModels() {
522
+ async getModels(config) {
530
523
  try {
531
- const response = await this._get("models");
524
+ const response = await this._get("models", {
525
+ signal: config?.signal
526
+ });
532
527
  const data = await this._parseModelsResponse(response);
533
528
  return this._filterAndTransformModels(data.models);
534
529
  } catch (e) {
530
+ if (e instanceof ChatLunaError) {
531
+ throw e;
532
+ }
535
533
  const error = new Error(
536
534
  "error when listing gemini models, Error: " + e.message
537
535
  );
@@ -704,27 +702,23 @@ var GeminiRequester = class extends ModelRequester {
704
702
  async *_processChunks(iterable) {
705
703
  let reasoningContent = "";
706
704
  let errorCount = 0;
707
- const functionCall = {
708
- name: "",
709
- args: "",
710
- arguments: ""
711
- };
705
+ let functionIndex = 0;
712
706
  for await (const chunk of iterable) {
713
707
  try {
714
- const { updatedContent, updatedReasoning } = await this._processChunk(
708
+ const { updatedContent, updatedReasoning, updatedToolCalling } = await this._processChunk(
715
709
  chunk,
716
710
  reasoningContent,
717
- functionCall
711
+ functionIndex
718
712
  );
719
713
  if (updatedReasoning !== reasoningContent) {
720
714
  reasoningContent = updatedReasoning;
721
715
  yield { type: "reasoning", content: reasoningContent };
722
716
  continue;
723
717
  }
724
- if (updatedContent || functionCall.name) {
718
+ if (updatedContent || updatedToolCalling) {
725
719
  const messageChunk = this._createMessageChunk(
726
720
  updatedContent,
727
- functionCall,
721
+ updatedToolCalling,
728
722
  this.ctx.chatluna_storage != null ? void 0 : partAsTypeCheck(
729
723
  chunk,
730
724
  (part) => part["inlineData"] != null
@@ -736,6 +730,9 @@ var GeminiRequester = class extends ModelRequester {
736
730
  });
737
731
  yield { type: "generation", generation: generationChunk };
738
732
  }
733
+ if (updatedToolCalling) {
734
+ functionIndex++;
735
+ }
739
736
  } catch (e) {
740
737
  if (errorCount > 5) {
741
738
  logger.error("error with chunk", chunk);
@@ -750,7 +747,7 @@ var GeminiRequester = class extends ModelRequester {
750
747
  }
751
748
  }
752
749
  }
753
- async _processChunk(chunk, reasoningContent, functionCall) {
750
+ async _processChunk(chunk, reasoningContent, functionIndex) {
754
751
  const messagePart = partAsType(chunk);
755
752
  const chatFunctionCallingPart = partAsType(chunk);
756
753
  const imagePart = partAsTypeCheck(
@@ -787,30 +784,25 @@ var GeminiRequester = class extends ModelRequester {
787
784
  }
788
785
  }
789
786
  const deltaFunctionCall = chatFunctionCallingPart?.functionCall;
787
+ let updatedToolCalling;
790
788
  if (deltaFunctionCall) {
791
- this._updateFunctionCall(functionCall, deltaFunctionCall);
789
+ updatedToolCalling = this._createToolCallChunk(
790
+ deltaFunctionCall,
791
+ functionIndex
792
+ );
792
793
  }
793
794
  return {
794
795
  updatedContent: messageContent,
795
- updatedReasoning: reasoningContent
796
+ updatedReasoning: reasoningContent,
797
+ updatedToolCalling
796
798
  };
797
799
  }
798
- _updateFunctionCall(functionCall, deltaFunctionCall) {
799
- let args = deltaFunctionCall.args;
800
- try {
801
- let parsedArgs = JSON.parse(args);
802
- if (typeof parsedArgs !== "string") {
803
- args = parsedArgs;
804
- }
805
- parsedArgs = JSON.parse(args);
806
- if (typeof parsedArgs !== "string") {
807
- args = parsedArgs;
808
- }
809
- } catch (e) {
810
- }
811
- functionCall.args = JSON.stringify(args);
812
- functionCall.name = deltaFunctionCall.name;
813
- functionCall.arguments = deltaFunctionCall.args;
800
+ _createToolCallChunk(deltaFunctionCall, functionIndex) {
801
+ return {
802
+ name: deltaFunctionCall?.name,
803
+ args: JSON.stringify(deltaFunctionCall.args),
804
+ id: deltaFunctionCall.id ?? `function_call_${functionIndex}`
805
+ };
814
806
  }
815
807
  _handleFinalContent(reasoningContent, groundingContent) {
816
808
  if (reasoningContent.length > 0) {
@@ -833,15 +825,10 @@ ${groundingContent}`
833
825
  }
834
826
  _createMessageChunk(content, functionCall, imagePart) {
835
827
  const messageChunk = new AIMessageChunk({
836
- content: content ?? ""
828
+ content: content ?? "",
829
+ tool_call_chunks: [functionCall].filter(Boolean)
837
830
  });
838
831
  messageChunk.additional_kwargs = {
839
- function_call: functionCall.name.length > 0 ? {
840
- name: functionCall.name,
841
- arguments: functionCall.args,
842
- args: functionCall.arguments
843
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
844
- } : void 0,
845
832
  images: imagePart ? [
846
833
  `data:${imagePart.inlineData.mimeType ?? "image/png"};base64,${imagePart.inlineData.data}`
847
834
  ] : void 0
@@ -864,11 +851,12 @@ ${groundingContent}`
864
851
  ...params
865
852
  });
866
853
  }
867
- _get(url) {
854
+ _get(url, params = {}) {
868
855
  const requestUrl = this._concatUrl(url);
869
856
  return this._plugin.fetch(requestUrl, {
870
857
  method: "GET",
871
- headers: this._buildHeaders()
858
+ headers: this._buildHeaders(),
859
+ ...params
872
860
  });
873
861
  }
874
862
  _concatUrl(url) {
@@ -916,9 +904,9 @@ var GeminiClient = class extends PlatformModelAndEmbeddingsClient {
916
904
  get logger() {
917
905
  return logger;
918
906
  }
919
- async refreshModels() {
907
+ async refreshModels(config) {
920
908
  try {
921
- const rawModels = await this._requester.getModels();
909
+ const rawModels = await this._requester.getModels(config);
922
910
  if (!rawModels.length) {
923
911
  throw new ChatLunaError2(
924
912
  ChatLunaErrorCode2.MODEL_INIT_ERROR,
@@ -939,7 +927,7 @@ var GeminiClient = class extends PlatformModelAndEmbeddingsClient {
939
927
  if (model.name.includes("gemini-2.5") && !model.name.includes("pro") && !model.name.includes("image")) {
940
928
  if (!model.name.includes("-thinking")) {
941
929
  models.push(
942
- { ...info, name: model.name + "-nonthinking" },
930
+ { ...info, name: model.name + "-non-thinking" },
943
931
  { ...info, name: model.name + "-thinking" },
944
932
  info
945
933
  );
@@ -952,6 +940,9 @@ var GeminiClient = class extends PlatformModelAndEmbeddingsClient {
952
940
  }
953
941
  return models;
954
942
  } catch (e) {
943
+ if (e instanceof ChatLunaError2) {
944
+ throw e;
945
+ }
955
946
  throw new ChatLunaError2(ChatLunaErrorCode2.MODEL_INIT_ERROR, e);
956
947
  }
957
948
  }
@@ -989,8 +980,7 @@ function apply(ctx, config) {
989
980
  const plugin = new ChatLunaPlugin(ctx, config, config.platform);
990
981
  logger = createLogger(ctx, "chatluna-gemini-adapter");
991
982
  ctx.on("ready", async () => {
992
- plugin.registerToService();
993
- await plugin.parseConfig((config2) => {
983
+ plugin.parseConfig((config2) => {
994
984
  return config2.apiKeys.map(([apiKey, apiEndpoint]) => {
995
985
  return {
996
986
  apiKey,
@@ -5,6 +5,7 @@ import { Config } from '.';
5
5
  import { GeminiModelInfo } from './types';
6
6
  import { ChatLunaPlugin } from 'koishi-plugin-chatluna/services/chat';
7
7
  import { Context } from 'koishi';
8
+ import { RunnableConfig } from '@langchain/core/runnables';
8
9
  export declare class GeminiRequester extends ModelRequester implements EmbeddingsRequester {
9
10
  _pluginConfig: Config;
10
11
  constructor(ctx: Context, _configPool: ClientConfigPool<ClientConfig>, _pluginConfig: Config, _plugin: ChatLunaPlugin);
@@ -15,7 +16,7 @@ export declare class GeminiRequester extends ModelRequester implements Embedding
15
16
  private _prepareEmbeddingsInput;
16
17
  private _createEmbeddingsRequest;
17
18
  private _processEmbeddingsResponse;
18
- getModels(): Promise<GeminiModelInfo[]>;
19
+ getModels(config?: RunnableConfig): Promise<GeminiModelInfo[]>;
19
20
  private _parseModelsResponse;
20
21
  private _filterAndTransformModels;
21
22
  private _processResponse;
@@ -26,7 +27,7 @@ export declare class GeminiRequester extends ModelRequester implements Embedding
26
27
  private _processCandidateChunk;
27
28
  private _processChunks;
28
29
  private _processChunk;
29
- private _updateFunctionCall;
30
+ private _createToolCallChunk;
30
31
  private _handleFinalContent;
31
32
  private _createMessageChunk;
32
33
  private _post;
package/lib/types.d.ts CHANGED
@@ -23,12 +23,14 @@ export type ChatFunctionCallingPart = {
23
23
  functionCall: {
24
24
  name: string;
25
25
  args?: any;
26
+ id?: string;
26
27
  };
27
28
  };
28
29
  export type ChatFunctionResponsePart = {
29
30
  functionResponse: {
30
31
  name: string;
31
32
  response: any;
33
+ id?: string;
32
34
  };
33
35
  };
34
36
  export interface 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.0-alpha.1",
4
+ "version": "1.3.0-alpha.10",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "lib/index.mjs",
7
7
  "typings": "lib/index.d.ts",
@@ -34,16 +34,16 @@
34
34
  },
35
35
  "resolutions": {
36
36
  "@langchain/core": "0.3.62",
37
- "js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.19"
37
+ "js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.21"
38
38
  },
39
39
  "overrides": {
40
40
  "@langchain/core": "0.3.62",
41
- "js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.19"
41
+ "js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.21"
42
42
  },
43
43
  "pnpm": {
44
44
  "overrides": {
45
45
  "@langchain/core": "0.3.62",
46
- "js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.19"
46
+ "js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.21"
47
47
  }
48
48
  },
49
49
  "engines": {
@@ -62,9 +62,9 @@
62
62
  "adapter"
63
63
  ],
64
64
  "dependencies": {
65
- "@chatluna/v1-shared-adapter": "^1.0.6",
65
+ "@chatluna/v1-shared-adapter": "^1.0.9",
66
66
  "@langchain/core": "0.3.62",
67
- "zod": "^3.25.0-canary.20250211T214501",
67
+ "zod": "3.25.76",
68
68
  "zod-to-json-schema": "^3.24.5"
69
69
  },
70
70
  "devDependencies": {
@@ -73,8 +73,8 @@
73
73
  },
74
74
  "peerDependencies": {
75
75
  "koishi": "^4.18.7",
76
- "koishi-plugin-chatluna": "^1.3.0-alpha.26",
77
- "koishi-plugin-chatluna-storage-service": "^0.0.8"
76
+ "koishi-plugin-chatluna": "^1.3.0-alpha.43",
77
+ "koishi-plugin-chatluna-storage-service": "^0.0.9"
78
78
  },
79
79
  "peerDependenciesMeta": {
80
80
  "koishi-plugin-chatluna-storage-service": {