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 +2 -1
- package/lib/index.cjs +70 -80
- package/lib/index.mjs +65 -75
- package/lib/requester.d.ts +3 -2
- package/lib/types.d.ts +2 -0
- package/package.json +8 -8
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
123
|
+
if (typeof result === "string") return { response: result };
|
|
124
|
+
if (Array.isArray(result)) return { response: result };
|
|
125
|
+
return result;
|
|
133
126
|
} catch {
|
|
134
|
-
return {
|
|
127
|
+
return { response: args };
|
|
135
128
|
}
|
|
136
129
|
}
|
|
137
130
|
__name(parseJsonArgs, "parseJsonArgs");
|
|
138
131
|
function processFunctionMessage(message) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
132
|
+
if (message["tool_calls"]) {
|
|
133
|
+
message = message;
|
|
134
|
+
const toolCalls = message.tool_calls;
|
|
142
135
|
return {
|
|
143
|
-
role: "
|
|
144
|
-
parts:
|
|
145
|
-
{
|
|
136
|
+
role: "model",
|
|
137
|
+
parts: toolCalls.map((toolCall) => {
|
|
138
|
+
return {
|
|
146
139
|
functionCall: {
|
|
147
|
-
name:
|
|
148
|
-
args:
|
|
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: "
|
|
150
|
+
role: "user",
|
|
156
151
|
parts: [
|
|
157
152
|
{
|
|
158
153
|
functionResponse: {
|
|
159
154
|
name: message.name,
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|
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 "
|
|
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("-
|
|
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
|
-
|
|
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
|
-
|
|
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 ||
|
|
721
|
+
if (updatedContent || updatedToolCalling) {
|
|
728
722
|
const messageChunk = this._createMessageChunk(
|
|
729
723
|
updatedContent,
|
|
730
|
-
|
|
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,
|
|
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.
|
|
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
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
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") ?
|
|
924
|
+
type: model.name.includes("embedding") ? import_types2.ModelType.embeddings : import_types2.ModelType.llm,
|
|
937
925
|
capabilities: [
|
|
938
|
-
|
|
939
|
-
|
|
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 + "-
|
|
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 ===
|
|
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.
|
|
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 {
|
|
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.
|
|
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
|
-
|
|
120
|
+
if (typeof result === "string") return { response: result };
|
|
121
|
+
if (Array.isArray(result)) return { response: result };
|
|
122
|
+
return result;
|
|
130
123
|
} catch {
|
|
131
|
-
return {
|
|
124
|
+
return { response: args };
|
|
132
125
|
}
|
|
133
126
|
}
|
|
134
127
|
__name(parseJsonArgs, "parseJsonArgs");
|
|
135
128
|
function processFunctionMessage(message) {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const
|
|
129
|
+
if (message["tool_calls"]) {
|
|
130
|
+
message = message;
|
|
131
|
+
const toolCalls = message.tool_calls;
|
|
139
132
|
return {
|
|
140
|
-
role: "
|
|
141
|
-
parts:
|
|
142
|
-
{
|
|
133
|
+
role: "model",
|
|
134
|
+
parts: toolCalls.map((toolCall) => {
|
|
135
|
+
return {
|
|
143
136
|
functionCall: {
|
|
144
|
-
name:
|
|
145
|
-
args:
|
|
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: "
|
|
147
|
+
role: "user",
|
|
153
148
|
parts: [
|
|
154
149
|
{
|
|
155
150
|
functionResponse: {
|
|
156
151
|
name: message.name,
|
|
157
|
-
|
|
158
|
-
|
|
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
|
|
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 "
|
|
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("-
|
|
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
|
-
|
|
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
|
-
|
|
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 ||
|
|
718
|
+
if (updatedContent || updatedToolCalling) {
|
|
725
719
|
const messageChunk = this._createMessageChunk(
|
|
726
720
|
updatedContent,
|
|
727
|
-
|
|
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,
|
|
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.
|
|
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
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
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 + "-
|
|
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.
|
|
993
|
-
await plugin.parseConfig((config2) => {
|
|
983
|
+
plugin.parseConfig((config2) => {
|
|
994
984
|
return config2.apiKeys.map(([apiKey, apiEndpoint]) => {
|
|
995
985
|
return {
|
|
996
986
|
apiKey,
|
package/lib/requester.d.ts
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
65
|
+
"@chatluna/v1-shared-adapter": "^1.0.9",
|
|
66
66
|
"@langchain/core": "0.3.62",
|
|
67
|
-
"zod": "
|
|
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.
|
|
77
|
-
"koishi-plugin-chatluna-storage-service": "^0.0.
|
|
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": {
|