koishi-plugin-chatluna-google-gemini-adapter 1.3.0-alpha.2 → 1.3.0-alpha.3

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
@@ -55,7 +55,7 @@ var import_types = 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
58
- var import_messages = require("@langchain/core/messages");
58
+ var import_messages2 = require("@langchain/core/messages");
59
59
  var import_outputs = require("@langchain/core/outputs");
60
60
  var import_api = require("koishi-plugin-chatluna/llm-core/platform/api");
61
61
  var import_error = require("koishi-plugin-chatluna/utils/error");
@@ -63,6 +63,7 @@ var import_sse = require("koishi-plugin-chatluna/utils/sse");
63
63
  var import_stream = require("koishi-plugin-chatluna/utils/stream");
64
64
 
65
65
  // src/utils.ts
66
+ var import_messages = require("@langchain/core/messages");
66
67
  var import_zod_to_json_schema = require("zod-to-json-schema");
67
68
  var import_v1_shared_adapter = require("@chatluna/v1-shared-adapter");
68
69
  var import_string = require("koishi-plugin-chatluna/utils/string");
@@ -71,7 +72,7 @@ async function langchainMessageToGeminiMessage(messages, plugin, model) {
71
72
  return Promise.all(
72
73
  messages.map(async (message) => {
73
74
  const role = messageTypeToGeminiRole(message.getType());
74
- const hasFunctionCall = message.additional_kwargs?.function_call != null;
75
+ const hasFunctionCall = message.tool_calls != null;
75
76
  if (role === "function" || hasFunctionCall) {
76
77
  return processFunctionMessage(message);
77
78
  }
@@ -117,15 +118,6 @@ function extractSystemMessages(messages) {
117
118
  ];
118
119
  }
119
120
  __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
121
  function parseJsonArgs(args) {
130
122
  try {
131
123
  const result = JSON.parse(args);
@@ -136,31 +128,29 @@ function parseJsonArgs(args) {
136
128
  }
137
129
  __name(parseJsonArgs, "parseJsonArgs");
138
130
  function processFunctionMessage(message) {
139
- const hasFunctionCall = message.additional_kwargs?.function_call != null;
140
- if (hasFunctionCall) {
141
- const functionCall = message.additional_kwargs.function_call;
131
+ if (message instanceof import_messages.AIMessageChunk || message instanceof import_messages.AIMessage) {
132
+ const toolCalls = message.tool_calls;
142
133
  return {
143
- role: "function",
144
- parts: [
145
- {
134
+ role: "model",
135
+ parts: toolCalls.map((toolCall) => {
136
+ return {
146
137
  functionCall: {
147
- name: functionCall.name,
148
- args: parseJsonArgs(functionCall.arguments)
138
+ name: toolCall.name,
139
+ args: toolCall.args,
140
+ id: toolCall.id
149
141
  }
150
- }
151
- ]
142
+ };
143
+ })
152
144
  };
153
145
  }
154
146
  return {
155
- role: "function",
147
+ role: "user",
156
148
  parts: [
157
149
  {
158
150
  functionResponse: {
159
151
  name: message.name,
160
- response: {
161
- name: message.name,
162
- content: parseJsonSafely(message.content)
163
- }
152
+ id: message.tool_call_id,
153
+ response: parseJsonArgs(message.content)
164
154
  }
165
155
  }
166
156
  ]
@@ -314,7 +304,7 @@ function messageTypeToGeminiRole(type) {
314
304
  return "model";
315
305
  case "human":
316
306
  return "user";
317
- case "function":
307
+ case "tool":
318
308
  return "function";
319
309
  default:
320
310
  throw new Error(`Unknown message type: ${type}`);
@@ -707,27 +697,23 @@ var GeminiRequester = class extends import_api.ModelRequester {
707
697
  async *_processChunks(iterable) {
708
698
  let reasoningContent = "";
709
699
  let errorCount = 0;
710
- const functionCall = {
711
- name: "",
712
- args: "",
713
- arguments: ""
714
- };
700
+ let functionIndex = 0;
715
701
  for await (const chunk of iterable) {
716
702
  try {
717
- const { updatedContent, updatedReasoning } = await this._processChunk(
703
+ const { updatedContent, updatedReasoning, updatedToolCalling } = await this._processChunk(
718
704
  chunk,
719
705
  reasoningContent,
720
- functionCall
706
+ functionIndex
721
707
  );
722
708
  if (updatedReasoning !== reasoningContent) {
723
709
  reasoningContent = updatedReasoning;
724
710
  yield { type: "reasoning", content: reasoningContent };
725
711
  continue;
726
712
  }
727
- if (updatedContent || functionCall.name) {
713
+ if (updatedContent || updatedToolCalling) {
728
714
  const messageChunk = this._createMessageChunk(
729
715
  updatedContent,
730
- functionCall,
716
+ updatedToolCalling,
731
717
  this.ctx.chatluna_storage != null ? void 0 : partAsTypeCheck(
732
718
  chunk,
733
719
  (part) => part["inlineData"] != null
@@ -739,6 +725,9 @@ var GeminiRequester = class extends import_api.ModelRequester {
739
725
  });
740
726
  yield { type: "generation", generation: generationChunk };
741
727
  }
728
+ if (updatedToolCalling) {
729
+ functionIndex++;
730
+ }
742
731
  } catch (e) {
743
732
  if (errorCount > 5) {
744
733
  logger.error("error with chunk", chunk);
@@ -753,7 +742,7 @@ var GeminiRequester = class extends import_api.ModelRequester {
753
742
  }
754
743
  }
755
744
  }
756
- async _processChunk(chunk, reasoningContent, functionCall) {
745
+ async _processChunk(chunk, reasoningContent, functionIndex) {
757
746
  const messagePart = partAsType(chunk);
758
747
  const chatFunctionCallingPart = partAsType(chunk);
759
748
  const imagePart = partAsTypeCheck(
@@ -790,30 +779,25 @@ var GeminiRequester = class extends import_api.ModelRequester {
790
779
  }
791
780
  }
792
781
  const deltaFunctionCall = chatFunctionCallingPart?.functionCall;
782
+ let updatedToolCalling;
793
783
  if (deltaFunctionCall) {
794
- this._updateFunctionCall(functionCall, deltaFunctionCall);
784
+ updatedToolCalling = this._createToolCallChunk(
785
+ deltaFunctionCall,
786
+ functionIndex
787
+ );
795
788
  }
796
789
  return {
797
790
  updatedContent: messageContent,
798
- updatedReasoning: reasoningContent
791
+ updatedReasoning: reasoningContent,
792
+ updatedToolCalling
799
793
  };
800
794
  }
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;
795
+ _createToolCallChunk(deltaFunctionCall, functionIndex) {
796
+ return {
797
+ name: deltaFunctionCall?.name,
798
+ args: JSON.stringify(deltaFunctionCall.args),
799
+ id: deltaFunctionCall.id ?? `function_call_${functionIndex}`
800
+ };
817
801
  }
818
802
  _handleFinalContent(reasoningContent, groundingContent) {
819
803
  if (reasoningContent.length > 0) {
@@ -822,7 +806,7 @@ var GeminiRequester = class extends import_api.ModelRequester {
822
806
  if (groundingContent.length > 0) {
823
807
  logger.debug(`grounding content: ${groundingContent}`);
824
808
  if (this._pluginConfig.groundingContentDisplay) {
825
- const groundingMessage = new import_messages.AIMessageChunk(
809
+ const groundingMessage = new import_messages2.AIMessageChunk(
826
810
  `
827
811
  ${groundingContent}`
828
812
  );
@@ -835,16 +819,11 @@ ${groundingContent}`
835
819
  }
836
820
  }
837
821
  _createMessageChunk(content, functionCall, imagePart) {
838
- const messageChunk = new import_messages.AIMessageChunk({
839
- content: content ?? ""
822
+ const messageChunk = new import_messages2.AIMessageChunk({
823
+ content: content ?? "",
824
+ tool_call_chunks: [functionCall].filter(Boolean)
840
825
  });
841
826
  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
827
  images: imagePart ? [
849
828
  `data:${imagePart.inlineData.mimeType ?? "image/png"};base64,${imagePart.inlineData.data}`
850
829
  ] : void 0
package/lib/index.mjs CHANGED
@@ -40,7 +40,7 @@ import {
40
40
 
41
41
  // src/requester.ts
42
42
  import {
43
- AIMessageChunk
43
+ AIMessageChunk as AIMessageChunk2
44
44
  } from "@langchain/core/messages";
45
45
  import { ChatGenerationChunk } from "@langchain/core/outputs";
46
46
  import {
@@ -54,6 +54,10 @@ import { checkResponse, sseIterable } from "koishi-plugin-chatluna/utils/sse";
54
54
  import { readableStreamToAsyncIterable } from "koishi-plugin-chatluna/utils/stream";
55
55
 
56
56
  // src/utils.ts
57
+ import {
58
+ AIMessage,
59
+ AIMessageChunk
60
+ } from "@langchain/core/messages";
57
61
  import { zodToJsonSchema } from "zod-to-json-schema";
58
62
  import {
59
63
  fetchImageUrl,
@@ -68,7 +72,7 @@ async function langchainMessageToGeminiMessage(messages, plugin, model) {
68
72
  return Promise.all(
69
73
  messages.map(async (message) => {
70
74
  const role = messageTypeToGeminiRole(message.getType());
71
- const hasFunctionCall = message.additional_kwargs?.function_call != null;
75
+ const hasFunctionCall = message.tool_calls != null;
72
76
  if (role === "function" || hasFunctionCall) {
73
77
  return processFunctionMessage(message);
74
78
  }
@@ -114,15 +118,6 @@ function extractSystemMessages(messages) {
114
118
  ];
115
119
  }
116
120
  __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
121
  function parseJsonArgs(args) {
127
122
  try {
128
123
  const result = JSON.parse(args);
@@ -133,31 +128,29 @@ function parseJsonArgs(args) {
133
128
  }
134
129
  __name(parseJsonArgs, "parseJsonArgs");
135
130
  function processFunctionMessage(message) {
136
- const hasFunctionCall = message.additional_kwargs?.function_call != null;
137
- if (hasFunctionCall) {
138
- const functionCall = message.additional_kwargs.function_call;
131
+ if (message instanceof AIMessageChunk || message instanceof AIMessage) {
132
+ const toolCalls = message.tool_calls;
139
133
  return {
140
- role: "function",
141
- parts: [
142
- {
134
+ role: "model",
135
+ parts: toolCalls.map((toolCall) => {
136
+ return {
143
137
  functionCall: {
144
- name: functionCall.name,
145
- args: parseJsonArgs(functionCall.arguments)
138
+ name: toolCall.name,
139
+ args: toolCall.args,
140
+ id: toolCall.id
146
141
  }
147
- }
148
- ]
142
+ };
143
+ })
149
144
  };
150
145
  }
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: message.tool_call_id,
153
+ response: parseJsonArgs(message.content)
161
154
  }
162
155
  }
163
156
  ]
@@ -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}`);
@@ -704,27 +697,23 @@ var GeminiRequester = class extends ModelRequester {
704
697
  async *_processChunks(iterable) {
705
698
  let reasoningContent = "";
706
699
  let errorCount = 0;
707
- const functionCall = {
708
- name: "",
709
- args: "",
710
- arguments: ""
711
- };
700
+ let functionIndex = 0;
712
701
  for await (const chunk of iterable) {
713
702
  try {
714
- const { updatedContent, updatedReasoning } = await this._processChunk(
703
+ const { updatedContent, updatedReasoning, updatedToolCalling } = await this._processChunk(
715
704
  chunk,
716
705
  reasoningContent,
717
- functionCall
706
+ functionIndex
718
707
  );
719
708
  if (updatedReasoning !== reasoningContent) {
720
709
  reasoningContent = updatedReasoning;
721
710
  yield { type: "reasoning", content: reasoningContent };
722
711
  continue;
723
712
  }
724
- if (updatedContent || functionCall.name) {
713
+ if (updatedContent || updatedToolCalling) {
725
714
  const messageChunk = this._createMessageChunk(
726
715
  updatedContent,
727
- functionCall,
716
+ updatedToolCalling,
728
717
  this.ctx.chatluna_storage != null ? void 0 : partAsTypeCheck(
729
718
  chunk,
730
719
  (part) => part["inlineData"] != null
@@ -736,6 +725,9 @@ var GeminiRequester = class extends ModelRequester {
736
725
  });
737
726
  yield { type: "generation", generation: generationChunk };
738
727
  }
728
+ if (updatedToolCalling) {
729
+ functionIndex++;
730
+ }
739
731
  } catch (e) {
740
732
  if (errorCount > 5) {
741
733
  logger.error("error with chunk", chunk);
@@ -750,7 +742,7 @@ var GeminiRequester = class extends ModelRequester {
750
742
  }
751
743
  }
752
744
  }
753
- async _processChunk(chunk, reasoningContent, functionCall) {
745
+ async _processChunk(chunk, reasoningContent, functionIndex) {
754
746
  const messagePart = partAsType(chunk);
755
747
  const chatFunctionCallingPart = partAsType(chunk);
756
748
  const imagePart = partAsTypeCheck(
@@ -787,30 +779,25 @@ var GeminiRequester = class extends ModelRequester {
787
779
  }
788
780
  }
789
781
  const deltaFunctionCall = chatFunctionCallingPart?.functionCall;
782
+ let updatedToolCalling;
790
783
  if (deltaFunctionCall) {
791
- this._updateFunctionCall(functionCall, deltaFunctionCall);
784
+ updatedToolCalling = this._createToolCallChunk(
785
+ deltaFunctionCall,
786
+ functionIndex
787
+ );
792
788
  }
793
789
  return {
794
790
  updatedContent: messageContent,
795
- updatedReasoning: reasoningContent
791
+ updatedReasoning: reasoningContent,
792
+ updatedToolCalling
796
793
  };
797
794
  }
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;
795
+ _createToolCallChunk(deltaFunctionCall, functionIndex) {
796
+ return {
797
+ name: deltaFunctionCall?.name,
798
+ args: JSON.stringify(deltaFunctionCall.args),
799
+ id: deltaFunctionCall.id ?? `function_call_${functionIndex}`
800
+ };
814
801
  }
815
802
  _handleFinalContent(reasoningContent, groundingContent) {
816
803
  if (reasoningContent.length > 0) {
@@ -819,7 +806,7 @@ var GeminiRequester = class extends ModelRequester {
819
806
  if (groundingContent.length > 0) {
820
807
  logger.debug(`grounding content: ${groundingContent}`);
821
808
  if (this._pluginConfig.groundingContentDisplay) {
822
- const groundingMessage = new AIMessageChunk(
809
+ const groundingMessage = new AIMessageChunk2(
823
810
  `
824
811
  ${groundingContent}`
825
812
  );
@@ -832,16 +819,11 @@ ${groundingContent}`
832
819
  }
833
820
  }
834
821
  _createMessageChunk(content, functionCall, imagePart) {
835
- const messageChunk = new AIMessageChunk({
836
- content: content ?? ""
822
+ const messageChunk = new AIMessageChunk2({
823
+ content: content ?? "",
824
+ tool_call_chunks: [functionCall].filter(Boolean)
837
825
  });
838
826
  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
827
  images: imagePart ? [
846
828
  `data:${imagePart.inlineData.mimeType ?? "image/png"};base64,${imagePart.inlineData.data}`
847
829
  ] : void 0
@@ -26,7 +26,7 @@ export declare class GeminiRequester extends ModelRequester implements Embedding
26
26
  private _processCandidateChunk;
27
27
  private _processChunks;
28
28
  private _processChunk;
29
- private _updateFunctionCall;
29
+ private _createToolCallChunk;
30
30
  private _handleFinalContent;
31
31
  private _createMessageChunk;
32
32
  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.2",
4
+ "version": "1.3.0-alpha.3",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "lib/index.mjs",
7
7
  "typings": "lib/index.d.ts",
@@ -73,7 +73,7 @@
73
73
  },
74
74
  "peerDependencies": {
75
75
  "koishi": "^4.18.7",
76
- "koishi-plugin-chatluna": "^1.3.0-alpha.28",
76
+ "koishi-plugin-chatluna": "^1.3.0-alpha.30",
77
77
  "koishi-plugin-chatluna-storage-service": "^0.0.8"
78
78
  },
79
79
  "peerDependenciesMeta": {