koishi-plugin-chatluna-google-gemini-adapter 1.2.21 → 1.2.22
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 +121 -110
- package/lib/index.mjs +124 -107
- package/lib/utils.d.ts +3 -2
- package/package.json +3 -3
package/lib/index.cjs
CHANGED
|
@@ -65,97 +65,28 @@ var import_stream = require("koishi-plugin-chatluna/utils/stream");
|
|
|
65
65
|
// src/utils.ts
|
|
66
66
|
var import_messages = require("@langchain/core/messages");
|
|
67
67
|
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
functionResponse: rawMessage.additional_kwargs?.function_call != null ? void 0 : {
|
|
78
|
-
name: rawMessage.name,
|
|
79
|
-
response: {
|
|
80
|
-
name: rawMessage.name,
|
|
81
|
-
content: (() => {
|
|
82
|
-
try {
|
|
83
|
-
const result2 = JSON.parse(
|
|
84
|
-
rawMessage.content
|
|
85
|
-
);
|
|
86
|
-
if (typeof result2 === "string") {
|
|
87
|
-
return {
|
|
88
|
-
response: result2
|
|
89
|
-
};
|
|
90
|
-
} else {
|
|
91
|
-
return result2;
|
|
92
|
-
}
|
|
93
|
-
} catch (e) {
|
|
94
|
-
return {
|
|
95
|
-
response: rawMessage.content
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
})()
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
functionCall: rawMessage.additional_kwargs?.function_call != null ? {
|
|
102
|
-
name: rawMessage.additional_kwargs.function_call.name,
|
|
103
|
-
args: (() => {
|
|
104
|
-
try {
|
|
105
|
-
const result2 = JSON.parse(
|
|
106
|
-
rawMessage.additional_kwargs.function_call.arguments
|
|
107
|
-
);
|
|
108
|
-
if (typeof result2 === "string") {
|
|
109
|
-
return {
|
|
110
|
-
input: result2
|
|
111
|
-
};
|
|
112
|
-
} else {
|
|
113
|
-
return result2;
|
|
114
|
-
}
|
|
115
|
-
} catch (e) {
|
|
116
|
-
return {
|
|
117
|
-
input: rawMessage.additional_kwargs.function_call.arguments
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
})()
|
|
121
|
-
} : void 0
|
|
122
|
-
}
|
|
123
|
-
]
|
|
124
|
-
};
|
|
68
|
+
var import_v1_shared_adapter = require("@chatluna/v1-shared-adapter");
|
|
69
|
+
var import_string = require("koishi-plugin-chatluna/utils/string");
|
|
70
|
+
async function langchainMessageToGeminiMessage(messages, plugin, model) {
|
|
71
|
+
return Promise.all(
|
|
72
|
+
messages.map(async (message) => {
|
|
73
|
+
const role = messageTypeToGeminiRole(message.getType());
|
|
74
|
+
const hasFunctionCall = message.additional_kwargs?.function_call != null;
|
|
75
|
+
if (role === "function" || hasFunctionCall) {
|
|
76
|
+
return processFunctionMessage(message);
|
|
125
77
|
}
|
|
126
|
-
const images = rawMessage.additional_kwargs.images;
|
|
127
78
|
const result = {
|
|
128
79
|
role,
|
|
129
|
-
parts: [
|
|
130
|
-
{
|
|
131
|
-
text: rawMessage.content
|
|
132
|
-
}
|
|
133
|
-
]
|
|
80
|
+
parts: []
|
|
134
81
|
};
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
result.parts.push({
|
|
140
|
-
inline_data: {
|
|
141
|
-
// base64 image match type
|
|
142
|
-
data,
|
|
143
|
-
mime_type: mineType ?? "image/jpeg"
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
result.parts = result.parts.filter((uncheckedPart) => {
|
|
148
|
-
const part = partAsTypeCheck(
|
|
149
|
-
uncheckedPart,
|
|
150
|
-
(part2) => part2["text"] != null
|
|
151
|
-
);
|
|
152
|
-
return part == null || part.text.length > 0;
|
|
153
|
-
});
|
|
82
|
+
result.parts = typeof message.content === "string" ? [{ text: message.content }] : await processGeminiContentParts(plugin, message.content);
|
|
83
|
+
const images = message.additional_kwargs.images;
|
|
84
|
+
if (images) {
|
|
85
|
+
processImageParts(result, images, model);
|
|
154
86
|
}
|
|
155
87
|
return result;
|
|
156
88
|
})
|
|
157
89
|
);
|
|
158
|
-
return mappedMessages;
|
|
159
90
|
}
|
|
160
91
|
__name(langchainMessageToGeminiMessage, "langchainMessageToGeminiMessage");
|
|
161
92
|
function extractSystemMessages(messages) {
|
|
@@ -188,6 +119,105 @@ function extractSystemMessages(messages) {
|
|
|
188
119
|
];
|
|
189
120
|
}
|
|
190
121
|
__name(extractSystemMessages, "extractSystemMessages");
|
|
122
|
+
function parseJsonSafely(content) {
|
|
123
|
+
try {
|
|
124
|
+
const result = JSON.parse(content);
|
|
125
|
+
return typeof result === "string" ? { response: result } : result;
|
|
126
|
+
} catch {
|
|
127
|
+
return { response: content };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
__name(parseJsonSafely, "parseJsonSafely");
|
|
131
|
+
function parseJsonArgs(args) {
|
|
132
|
+
try {
|
|
133
|
+
const result = JSON.parse(args);
|
|
134
|
+
return typeof result === "string" ? { input: result } : result;
|
|
135
|
+
} catch {
|
|
136
|
+
return { input: args };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
__name(parseJsonArgs, "parseJsonArgs");
|
|
140
|
+
function processFunctionMessage(message) {
|
|
141
|
+
const hasFunctionCall = message.additional_kwargs?.function_call != null;
|
|
142
|
+
if (hasFunctionCall) {
|
|
143
|
+
const functionCall = message.additional_kwargs.function_call;
|
|
144
|
+
return {
|
|
145
|
+
role: "function",
|
|
146
|
+
parts: [
|
|
147
|
+
{
|
|
148
|
+
functionCall: {
|
|
149
|
+
name: functionCall.name,
|
|
150
|
+
args: parseJsonArgs(functionCall.arguments)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
role: "function",
|
|
158
|
+
parts: [
|
|
159
|
+
{
|
|
160
|
+
functionResponse: {
|
|
161
|
+
name: message.name,
|
|
162
|
+
response: {
|
|
163
|
+
name: message.name,
|
|
164
|
+
content: parseJsonSafely(message.content)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
__name(processFunctionMessage, "processFunctionMessage");
|
|
172
|
+
function processImageParts(result, images, model) {
|
|
173
|
+
if (!((model.includes("vision") || model.includes("gemini") || model.includes("gemma")) && !model.includes("gemini-1.0"))) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
for (const image of images) {
|
|
177
|
+
const mineType = image.split(";")?.[0]?.split(":")?.[1] ?? "image/jpeg";
|
|
178
|
+
const data = image.replace(/^data:image\/\w+;base64,/, "");
|
|
179
|
+
result.parts.push({
|
|
180
|
+
inline_data: { data, mime_type: mineType }
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
result.parts = result.parts.filter((uncheckedPart) => {
|
|
184
|
+
const part = partAsTypeCheck(
|
|
185
|
+
uncheckedPart,
|
|
186
|
+
(part2) => part2["text"] != null
|
|
187
|
+
);
|
|
188
|
+
return part == null || part.text.length > 0;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
__name(processImageParts, "processImageParts");
|
|
192
|
+
async function processGeminiImageContent(plugin, part) {
|
|
193
|
+
let url;
|
|
194
|
+
try {
|
|
195
|
+
url = await (0, import_v1_shared_adapter.fetchImageUrl)(plugin, part);
|
|
196
|
+
} catch (e) {
|
|
197
|
+
url = typeof part.image_url === "string" ? part.image_url : part.image_url.url;
|
|
198
|
+
logger.warn(`Failed to fetch image url: ${url}`, e);
|
|
199
|
+
}
|
|
200
|
+
const mineType = url.match(/^data:([^;]+);base64,/)?.[1] ?? "image/jpeg";
|
|
201
|
+
const data = url.replace(/^data:image\/\w+;base64,/, "");
|
|
202
|
+
return {
|
|
203
|
+
inline_data: { data, mime_type: mineType }
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
__name(processGeminiImageContent, "processGeminiImageContent");
|
|
207
|
+
async function processGeminiContentParts(plugin, content) {
|
|
208
|
+
return Promise.all(
|
|
209
|
+
content.map(async (part) => {
|
|
210
|
+
if ((0, import_string.isMessageContentText)(part)) {
|
|
211
|
+
return { text: part.text };
|
|
212
|
+
}
|
|
213
|
+
if ((0, import_string.isMessageContentImageUrl)(part)) {
|
|
214
|
+
return await processGeminiImageContent(plugin, part);
|
|
215
|
+
}
|
|
216
|
+
return part;
|
|
217
|
+
})
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
__name(processGeminiContentParts, "processGeminiContentParts");
|
|
191
221
|
function partAsType(part) {
|
|
192
222
|
return part;
|
|
193
223
|
}
|
|
@@ -265,7 +295,7 @@ function formatToolsToGeminiAITools(tools, config, model) {
|
|
|
265
295
|
}
|
|
266
296
|
__name(formatToolsToGeminiAITools, "formatToolsToGeminiAITools");
|
|
267
297
|
function formatToolToGeminiAITool(tool) {
|
|
268
|
-
const parameters = removeAdditionalProperties(
|
|
298
|
+
const parameters = (0, import_v1_shared_adapter.removeAdditionalProperties)(
|
|
269
299
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
270
300
|
(0, import_zod_to_json_schema.zodToJsonSchema)(tool.schema, {
|
|
271
301
|
allowedAdditionalProperties: void 0
|
|
@@ -279,28 +309,6 @@ function formatToolToGeminiAITool(tool) {
|
|
|
279
309
|
};
|
|
280
310
|
}
|
|
281
311
|
__name(formatToolToGeminiAITool, "formatToolToGeminiAITool");
|
|
282
|
-
function removeAdditionalProperties(schema) {
|
|
283
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
284
|
-
const stack = [[schema, null]];
|
|
285
|
-
while (stack.length > 0) {
|
|
286
|
-
const [current] = stack.pop();
|
|
287
|
-
if (typeof current !== "object" || current === null) continue;
|
|
288
|
-
if (Object.hasOwn(current, "additionalProperties")) {
|
|
289
|
-
delete current["additionalProperties"];
|
|
290
|
-
}
|
|
291
|
-
if (Object.hasOwn(current, "$schema")) {
|
|
292
|
-
delete current["$schema"];
|
|
293
|
-
}
|
|
294
|
-
for (const key of Object.keys(current)) {
|
|
295
|
-
const value = current[key];
|
|
296
|
-
if (value && typeof value === "object") {
|
|
297
|
-
stack.push([value, key]);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
return schema;
|
|
302
|
-
}
|
|
303
|
-
__name(removeAdditionalProperties, "removeAdditionalProperties");
|
|
304
312
|
function messageTypeToGeminiRole(type) {
|
|
305
313
|
switch (type) {
|
|
306
314
|
case "system":
|
|
@@ -376,9 +384,10 @@ function createGenerationConfig(params, modelConfig, pluginConfig) {
|
|
|
376
384
|
};
|
|
377
385
|
}
|
|
378
386
|
__name(createGenerationConfig, "createGenerationConfig");
|
|
379
|
-
async function createChatGenerationParams(params, modelConfig, pluginConfig) {
|
|
387
|
+
async function createChatGenerationParams(params, plugin, modelConfig, pluginConfig) {
|
|
380
388
|
const geminiMessages = await langchainMessageToGeminiMessage(
|
|
381
389
|
params.input,
|
|
390
|
+
plugin,
|
|
382
391
|
modelConfig.model
|
|
383
392
|
);
|
|
384
393
|
const [systemInstruction, modelMessages] = extractSystemMessages(geminiMessages);
|
|
@@ -405,7 +414,7 @@ function isChatResponse(response) {
|
|
|
405
414
|
__name(isChatResponse, "isChatResponse");
|
|
406
415
|
|
|
407
416
|
// src/requester.ts
|
|
408
|
-
var
|
|
417
|
+
var import_string2 = require("koishi-plugin-chatluna/utils/string");
|
|
409
418
|
var GeminiRequester = class extends import_api.ModelRequester {
|
|
410
419
|
constructor(ctx, _configPool, _pluginConfig, _plugin) {
|
|
411
420
|
super(ctx, _configPool, _pluginConfig, _plugin);
|
|
@@ -437,6 +446,7 @@ var GeminiRequester = class extends import_api.ModelRequester {
|
|
|
437
446
|
`models/${modelConfig.model}:streamGenerateContent?alt=sse`,
|
|
438
447
|
await createChatGenerationParams(
|
|
439
448
|
params,
|
|
449
|
+
this._plugin,
|
|
440
450
|
modelConfig,
|
|
441
451
|
this._pluginConfig
|
|
442
452
|
),
|
|
@@ -458,9 +468,10 @@ var GeminiRequester = class extends import_api.ModelRequester {
|
|
|
458
468
|
const modelConfig = prepareModelConfig(params, this._pluginConfig);
|
|
459
469
|
try {
|
|
460
470
|
const response = await this._post(
|
|
461
|
-
`models/${modelConfig.model}:generateContent
|
|
471
|
+
`models/${modelConfig.model}:generateContent`,
|
|
462
472
|
await createChatGenerationParams(
|
|
463
473
|
params,
|
|
474
|
+
this._plugin,
|
|
464
475
|
modelConfig,
|
|
465
476
|
this._pluginConfig
|
|
466
477
|
),
|
|
@@ -726,7 +737,7 @@ var GeminiRequester = class extends import_api.ModelRequester {
|
|
|
726
737
|
);
|
|
727
738
|
const generationChunk = new import_outputs.ChatGenerationChunk({
|
|
728
739
|
message: messageChunk,
|
|
729
|
-
text: (0,
|
|
740
|
+
text: (0, import_string2.getMessageContent)(messageChunk.content) ?? ""
|
|
730
741
|
});
|
|
731
742
|
yield { type: "generation", generation: generationChunk };
|
|
732
743
|
}
|
package/lib/index.mjs
CHANGED
|
@@ -61,97 +61,34 @@ import {
|
|
|
61
61
|
SystemMessageChunk
|
|
62
62
|
} from "@langchain/core/messages";
|
|
63
63
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const result2 = JSON.parse(
|
|
80
|
-
rawMessage.content
|
|
81
|
-
);
|
|
82
|
-
if (typeof result2 === "string") {
|
|
83
|
-
return {
|
|
84
|
-
response: result2
|
|
85
|
-
};
|
|
86
|
-
} else {
|
|
87
|
-
return result2;
|
|
88
|
-
}
|
|
89
|
-
} catch (e) {
|
|
90
|
-
return {
|
|
91
|
-
response: rawMessage.content
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
})()
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
functionCall: rawMessage.additional_kwargs?.function_call != null ? {
|
|
98
|
-
name: rawMessage.additional_kwargs.function_call.name,
|
|
99
|
-
args: (() => {
|
|
100
|
-
try {
|
|
101
|
-
const result2 = JSON.parse(
|
|
102
|
-
rawMessage.additional_kwargs.function_call.arguments
|
|
103
|
-
);
|
|
104
|
-
if (typeof result2 === "string") {
|
|
105
|
-
return {
|
|
106
|
-
input: result2
|
|
107
|
-
};
|
|
108
|
-
} else {
|
|
109
|
-
return result2;
|
|
110
|
-
}
|
|
111
|
-
} catch (e) {
|
|
112
|
-
return {
|
|
113
|
-
input: rawMessage.additional_kwargs.function_call.arguments
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
})()
|
|
117
|
-
} : void 0
|
|
118
|
-
}
|
|
119
|
-
]
|
|
120
|
-
};
|
|
64
|
+
import {
|
|
65
|
+
fetchImageUrl,
|
|
66
|
+
removeAdditionalProperties
|
|
67
|
+
} from "@chatluna/v1-shared-adapter";
|
|
68
|
+
import {
|
|
69
|
+
isMessageContentImageUrl,
|
|
70
|
+
isMessageContentText
|
|
71
|
+
} from "koishi-plugin-chatluna/utils/string";
|
|
72
|
+
async function langchainMessageToGeminiMessage(messages, plugin, model) {
|
|
73
|
+
return Promise.all(
|
|
74
|
+
messages.map(async (message) => {
|
|
75
|
+
const role = messageTypeToGeminiRole(message.getType());
|
|
76
|
+
const hasFunctionCall = message.additional_kwargs?.function_call != null;
|
|
77
|
+
if (role === "function" || hasFunctionCall) {
|
|
78
|
+
return processFunctionMessage(message);
|
|
121
79
|
}
|
|
122
|
-
const images = rawMessage.additional_kwargs.images;
|
|
123
80
|
const result = {
|
|
124
81
|
role,
|
|
125
|
-
parts: [
|
|
126
|
-
{
|
|
127
|
-
text: rawMessage.content
|
|
128
|
-
}
|
|
129
|
-
]
|
|
82
|
+
parts: []
|
|
130
83
|
};
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
result.parts.push({
|
|
136
|
-
inline_data: {
|
|
137
|
-
// base64 image match type
|
|
138
|
-
data,
|
|
139
|
-
mime_type: mineType ?? "image/jpeg"
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
result.parts = result.parts.filter((uncheckedPart) => {
|
|
144
|
-
const part = partAsTypeCheck(
|
|
145
|
-
uncheckedPart,
|
|
146
|
-
(part2) => part2["text"] != null
|
|
147
|
-
);
|
|
148
|
-
return part == null || part.text.length > 0;
|
|
149
|
-
});
|
|
84
|
+
result.parts = typeof message.content === "string" ? [{ text: message.content }] : await processGeminiContentParts(plugin, message.content);
|
|
85
|
+
const images = message.additional_kwargs.images;
|
|
86
|
+
if (images) {
|
|
87
|
+
processImageParts(result, images, model);
|
|
150
88
|
}
|
|
151
89
|
return result;
|
|
152
90
|
})
|
|
153
91
|
);
|
|
154
|
-
return mappedMessages;
|
|
155
92
|
}
|
|
156
93
|
__name(langchainMessageToGeminiMessage, "langchainMessageToGeminiMessage");
|
|
157
94
|
function extractSystemMessages(messages) {
|
|
@@ -184,6 +121,105 @@ function extractSystemMessages(messages) {
|
|
|
184
121
|
];
|
|
185
122
|
}
|
|
186
123
|
__name(extractSystemMessages, "extractSystemMessages");
|
|
124
|
+
function parseJsonSafely(content) {
|
|
125
|
+
try {
|
|
126
|
+
const result = JSON.parse(content);
|
|
127
|
+
return typeof result === "string" ? { response: result } : result;
|
|
128
|
+
} catch {
|
|
129
|
+
return { response: content };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
__name(parseJsonSafely, "parseJsonSafely");
|
|
133
|
+
function parseJsonArgs(args) {
|
|
134
|
+
try {
|
|
135
|
+
const result = JSON.parse(args);
|
|
136
|
+
return typeof result === "string" ? { input: result } : result;
|
|
137
|
+
} catch {
|
|
138
|
+
return { input: args };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
__name(parseJsonArgs, "parseJsonArgs");
|
|
142
|
+
function processFunctionMessage(message) {
|
|
143
|
+
const hasFunctionCall = message.additional_kwargs?.function_call != null;
|
|
144
|
+
if (hasFunctionCall) {
|
|
145
|
+
const functionCall = message.additional_kwargs.function_call;
|
|
146
|
+
return {
|
|
147
|
+
role: "function",
|
|
148
|
+
parts: [
|
|
149
|
+
{
|
|
150
|
+
functionCall: {
|
|
151
|
+
name: functionCall.name,
|
|
152
|
+
args: parseJsonArgs(functionCall.arguments)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
role: "function",
|
|
160
|
+
parts: [
|
|
161
|
+
{
|
|
162
|
+
functionResponse: {
|
|
163
|
+
name: message.name,
|
|
164
|
+
response: {
|
|
165
|
+
name: message.name,
|
|
166
|
+
content: parseJsonSafely(message.content)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
__name(processFunctionMessage, "processFunctionMessage");
|
|
174
|
+
function processImageParts(result, images, model) {
|
|
175
|
+
if (!((model.includes("vision") || model.includes("gemini") || model.includes("gemma")) && !model.includes("gemini-1.0"))) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
for (const image of images) {
|
|
179
|
+
const mineType = image.split(";")?.[0]?.split(":")?.[1] ?? "image/jpeg";
|
|
180
|
+
const data = image.replace(/^data:image\/\w+;base64,/, "");
|
|
181
|
+
result.parts.push({
|
|
182
|
+
inline_data: { data, mime_type: mineType }
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
result.parts = result.parts.filter((uncheckedPart) => {
|
|
186
|
+
const part = partAsTypeCheck(
|
|
187
|
+
uncheckedPart,
|
|
188
|
+
(part2) => part2["text"] != null
|
|
189
|
+
);
|
|
190
|
+
return part == null || part.text.length > 0;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
__name(processImageParts, "processImageParts");
|
|
194
|
+
async function processGeminiImageContent(plugin, part) {
|
|
195
|
+
let url;
|
|
196
|
+
try {
|
|
197
|
+
url = await fetchImageUrl(plugin, part);
|
|
198
|
+
} catch (e) {
|
|
199
|
+
url = typeof part.image_url === "string" ? part.image_url : part.image_url.url;
|
|
200
|
+
logger.warn(`Failed to fetch image url: ${url}`, e);
|
|
201
|
+
}
|
|
202
|
+
const mineType = url.match(/^data:([^;]+);base64,/)?.[1] ?? "image/jpeg";
|
|
203
|
+
const data = url.replace(/^data:image\/\w+;base64,/, "");
|
|
204
|
+
return {
|
|
205
|
+
inline_data: { data, mime_type: mineType }
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
__name(processGeminiImageContent, "processGeminiImageContent");
|
|
209
|
+
async function processGeminiContentParts(plugin, content) {
|
|
210
|
+
return Promise.all(
|
|
211
|
+
content.map(async (part) => {
|
|
212
|
+
if (isMessageContentText(part)) {
|
|
213
|
+
return { text: part.text };
|
|
214
|
+
}
|
|
215
|
+
if (isMessageContentImageUrl(part)) {
|
|
216
|
+
return await processGeminiImageContent(plugin, part);
|
|
217
|
+
}
|
|
218
|
+
return part;
|
|
219
|
+
})
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
__name(processGeminiContentParts, "processGeminiContentParts");
|
|
187
223
|
function partAsType(part) {
|
|
188
224
|
return part;
|
|
189
225
|
}
|
|
@@ -275,28 +311,6 @@ function formatToolToGeminiAITool(tool) {
|
|
|
275
311
|
};
|
|
276
312
|
}
|
|
277
313
|
__name(formatToolToGeminiAITool, "formatToolToGeminiAITool");
|
|
278
|
-
function removeAdditionalProperties(schema) {
|
|
279
|
-
if (!schema || typeof schema !== "object") return schema;
|
|
280
|
-
const stack = [[schema, null]];
|
|
281
|
-
while (stack.length > 0) {
|
|
282
|
-
const [current] = stack.pop();
|
|
283
|
-
if (typeof current !== "object" || current === null) continue;
|
|
284
|
-
if (Object.hasOwn(current, "additionalProperties")) {
|
|
285
|
-
delete current["additionalProperties"];
|
|
286
|
-
}
|
|
287
|
-
if (Object.hasOwn(current, "$schema")) {
|
|
288
|
-
delete current["$schema"];
|
|
289
|
-
}
|
|
290
|
-
for (const key of Object.keys(current)) {
|
|
291
|
-
const value = current[key];
|
|
292
|
-
if (value && typeof value === "object") {
|
|
293
|
-
stack.push([value, key]);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return schema;
|
|
298
|
-
}
|
|
299
|
-
__name(removeAdditionalProperties, "removeAdditionalProperties");
|
|
300
314
|
function messageTypeToGeminiRole(type) {
|
|
301
315
|
switch (type) {
|
|
302
316
|
case "system":
|
|
@@ -372,9 +386,10 @@ function createGenerationConfig(params, modelConfig, pluginConfig) {
|
|
|
372
386
|
};
|
|
373
387
|
}
|
|
374
388
|
__name(createGenerationConfig, "createGenerationConfig");
|
|
375
|
-
async function createChatGenerationParams(params, modelConfig, pluginConfig) {
|
|
389
|
+
async function createChatGenerationParams(params, plugin, modelConfig, pluginConfig) {
|
|
376
390
|
const geminiMessages = await langchainMessageToGeminiMessage(
|
|
377
391
|
params.input,
|
|
392
|
+
plugin,
|
|
378
393
|
modelConfig.model
|
|
379
394
|
);
|
|
380
395
|
const [systemInstruction, modelMessages] = extractSystemMessages(geminiMessages);
|
|
@@ -433,6 +448,7 @@ var GeminiRequester = class extends ModelRequester {
|
|
|
433
448
|
`models/${modelConfig.model}:streamGenerateContent?alt=sse`,
|
|
434
449
|
await createChatGenerationParams(
|
|
435
450
|
params,
|
|
451
|
+
this._plugin,
|
|
436
452
|
modelConfig,
|
|
437
453
|
this._pluginConfig
|
|
438
454
|
),
|
|
@@ -454,9 +470,10 @@ var GeminiRequester = class extends ModelRequester {
|
|
|
454
470
|
const modelConfig = prepareModelConfig(params, this._pluginConfig);
|
|
455
471
|
try {
|
|
456
472
|
const response = await this._post(
|
|
457
|
-
`models/${modelConfig.model}:generateContent
|
|
473
|
+
`models/${modelConfig.model}:generateContent`,
|
|
458
474
|
await createChatGenerationParams(
|
|
459
475
|
params,
|
|
476
|
+
this._plugin,
|
|
460
477
|
modelConfig,
|
|
461
478
|
this._pluginConfig
|
|
462
479
|
),
|
package/lib/utils.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ import { StructuredTool } from '@langchain/core/tools';
|
|
|
3
3
|
import { ChatCompletionFunction, ChatCompletionResponseMessage, ChatCompletionResponseMessageRoleEnum, ChatPart, ChatResponse } from './types';
|
|
4
4
|
import { Config } from '.';
|
|
5
5
|
import { ModelRequestParams } from 'koishi-plugin-chatluna/llm-core/platform/api';
|
|
6
|
-
|
|
6
|
+
import { ChatLunaPlugin } from 'koishi-plugin-chatluna/services/chat';
|
|
7
|
+
export declare function langchainMessageToGeminiMessage(messages: BaseMessage[], plugin: ChatLunaPlugin, model?: string): Promise<ChatCompletionResponseMessage[]>;
|
|
7
8
|
export declare function extractSystemMessages(messages: ChatCompletionResponseMessage[]): [ChatCompletionResponseMessage, ChatCompletionResponseMessage[]];
|
|
8
9
|
export declare function partAsType<T extends ChatPart>(part: ChatPart): T;
|
|
9
10
|
export declare function partAsTypeCheck<T extends ChatPart>(part: ChatPart, check: (part: ChatPart & unknown) => boolean): T | undefined;
|
|
@@ -31,7 +32,7 @@ export declare function createGenerationConfig(params: ModelRequestParams, model
|
|
|
31
32
|
includeThoughts: boolean;
|
|
32
33
|
};
|
|
33
34
|
};
|
|
34
|
-
export declare function createChatGenerationParams(params: ModelRequestParams, modelConfig: ReturnType<typeof prepareModelConfig>, pluginConfig: Config): Promise<{
|
|
35
|
+
export declare function createChatGenerationParams(params: ModelRequestParams, plugin: ChatLunaPlugin, modelConfig: ReturnType<typeof prepareModelConfig>, pluginConfig: Config): Promise<{
|
|
35
36
|
contents: ChatCompletionResponseMessage[];
|
|
36
37
|
safetySettings: {
|
|
37
38
|
category: 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.2.
|
|
4
|
+
"version": "1.2.22",
|
|
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.
|
|
65
|
+
"@chatluna/v1-shared-adapter": "^1.0.5",
|
|
66
66
|
"@langchain/core": "^0.3.43",
|
|
67
67
|
"zod": "^3.25.0-canary.20250211T214501",
|
|
68
68
|
"zod-to-json-schema": "^3.24.5"
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
75
|
"koishi": "^4.18.7",
|
|
76
|
-
"koishi-plugin-chatluna": "^1.3.0-alpha.
|
|
76
|
+
"koishi-plugin-chatluna": "^1.3.0-alpha.17"
|
|
77
77
|
},
|
|
78
78
|
"koishi": {
|
|
79
79
|
"description": {
|