koishi-plugin-chatluna-google-gemini-adapter 1.0.0-beta.4 → 1.0.0-beta.7
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.js +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/requester.d.ts +1 -1
- package/lib/requester.js +67 -26
- package/lib/types.d.ts +26 -2
- package/lib/utils.d.ts +6 -2
- package/lib/utils.js +105 -7
- package/package.json +6 -4
package/lib/client.js
CHANGED
|
@@ -34,7 +34,7 @@ class GeminiClient extends client_1.PlatformModelAndEmbeddingsClient {
|
|
|
34
34
|
type: model.includes('embedding')
|
|
35
35
|
? types_1.ModelType.embeddings
|
|
36
36
|
: types_1.ModelType.llm,
|
|
37
|
-
functionCall:
|
|
37
|
+
functionCall: !model.includes('vision'),
|
|
38
38
|
supportMode: ['all']
|
|
39
39
|
};
|
|
40
40
|
});
|
package/lib/index.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ export interface Config extends ChatLunaPlugin.Config {
|
|
|
9
9
|
}
|
|
10
10
|
export declare const Config: Schema<Config>;
|
|
11
11
|
export declare const inject: string[];
|
|
12
|
-
export declare const name = "chatluna-gemini-adapter";
|
|
12
|
+
export declare const name = "chatluna-google-gemini-adapter";
|
package/lib/index.js
CHANGED
package/lib/requester.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EmbeddingsRequester, EmbeddingsRequestParams, ModelRequester, ModelRequestParams } from 'koishi-plugin-chatluna/lib/llm-core/platform/api';
|
|
2
2
|
import { ClientConfig } from 'koishi-plugin-chatluna/lib/llm-core/platform/config';
|
|
3
|
-
import { ChatGenerationChunk } from 'langchain/
|
|
3
|
+
import { ChatGenerationChunk } from '@langchain/core/outputs';
|
|
4
4
|
export declare class GeminiRequester extends ModelRequester implements EmbeddingsRequester {
|
|
5
5
|
private _config;
|
|
6
6
|
constructor(_config: ClientConfig);
|
package/lib/requester.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GeminiRequester = void 0;
|
|
4
4
|
const api_1 = require("koishi-plugin-chatluna/lib/llm-core/platform/api");
|
|
5
|
-
const
|
|
5
|
+
const messages_1 = require("@langchain/core/messages");
|
|
6
|
+
const outputs_1 = require("@langchain/core/outputs");
|
|
6
7
|
const error_1 = require("koishi-plugin-chatluna/lib/utils/error");
|
|
7
8
|
const sse_1 = require("koishi-plugin-chatluna/lib/utils/sse");
|
|
8
9
|
const utils_1 = require("./utils");
|
|
@@ -23,19 +24,19 @@ class GeminiRequester extends api_1.ModelRequester {
|
|
|
23
24
|
safetySettings: [
|
|
24
25
|
{
|
|
25
26
|
category: 'HARM_CATEGORY_HARASSMENT',
|
|
26
|
-
threshold: '
|
|
27
|
+
threshold: 'BLOCK_NONE'
|
|
27
28
|
},
|
|
28
29
|
{
|
|
29
30
|
category: 'HARM_CATEGORY_HATE_SPEECH',
|
|
30
|
-
threshold: '
|
|
31
|
+
threshold: 'BLOCK_NONE'
|
|
31
32
|
},
|
|
32
33
|
{
|
|
33
34
|
category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
|
|
34
|
-
threshold: '
|
|
35
|
+
threshold: 'BLOCK_NONE'
|
|
35
36
|
},
|
|
36
37
|
{
|
|
37
38
|
category: 'HARM_CATEGORY_DANGEROUS_CONTENT',
|
|
38
|
-
threshold: '
|
|
39
|
+
threshold: 'BLOCK_NONE'
|
|
39
40
|
}
|
|
40
41
|
],
|
|
41
42
|
generationConfig: {
|
|
@@ -45,7 +46,12 @@ class GeminiRequester extends api_1.ModelRequester {
|
|
|
45
46
|
? undefined
|
|
46
47
|
: params.maxTokens,
|
|
47
48
|
topP: params.topP
|
|
48
|
-
}
|
|
49
|
+
},
|
|
50
|
+
tools: !params.model.includes('vision') && params.tools != null
|
|
51
|
+
? {
|
|
52
|
+
functionDeclarations: (0, utils_1.formatToolsToGeminiAITools)(params.tools)
|
|
53
|
+
}
|
|
54
|
+
: undefined
|
|
49
55
|
}, {
|
|
50
56
|
signal: params.signal
|
|
51
57
|
});
|
|
@@ -55,43 +61,79 @@ class GeminiRequester extends api_1.ModelRequester {
|
|
|
55
61
|
const jsonParser = new json_1.JSONParser();
|
|
56
62
|
const writable = stream.writable.getWriter();
|
|
57
63
|
jsonParser.onEnd = async () => {
|
|
58
|
-
await writable.
|
|
64
|
+
await writable.close();
|
|
59
65
|
};
|
|
60
66
|
jsonParser.onValue = async ({ value }) => {
|
|
61
67
|
const transformValue = value;
|
|
62
68
|
if (transformValue.candidates && transformValue.candidates[0]) {
|
|
63
|
-
const parts = transformValue.candidates[0].content
|
|
64
|
-
.parts;
|
|
69
|
+
const parts = transformValue.candidates[0].content.parts;
|
|
65
70
|
if (parts.length < 1) {
|
|
66
71
|
throw new Error(JSON.stringify(value));
|
|
67
72
|
}
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
if (text) {
|
|
71
|
-
await writable.write(text);
|
|
73
|
+
for (const part of parts) {
|
|
74
|
+
await writable.write(part);
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
77
|
};
|
|
75
78
|
await (0, sse_1.sse)(response, async (rawData) => {
|
|
76
|
-
_1.logger.debug('chunk', rawData);
|
|
77
79
|
jsonParser.write(rawData);
|
|
78
80
|
return true;
|
|
79
|
-
});
|
|
81
|
+
}, 10);
|
|
80
82
|
let content = '';
|
|
81
83
|
let isVisionModel = params.model.includes('vision');
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
const functionCall = {
|
|
85
|
+
name: '',
|
|
86
|
+
args: '',
|
|
87
|
+
arguments: ''
|
|
88
|
+
};
|
|
89
|
+
for await (const chunk of iterable) {
|
|
90
|
+
const messagePart = (0, utils_1.partAsType)(chunk);
|
|
91
|
+
const chatFunctionCallingPart = (0, utils_1.partAsType)(chunk);
|
|
92
|
+
if (messagePart.text) {
|
|
93
|
+
content += messagePart.text;
|
|
94
|
+
// match /w*model:
|
|
95
|
+
if (isVisionModel && /\s*model:\s*/.test(content)) {
|
|
96
|
+
isVisionModel = false;
|
|
97
|
+
content = content.replace(/\s*model:\s*/, '');
|
|
98
|
+
}
|
|
85
99
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
100
|
+
if (chatFunctionCallingPart.functionCall) {
|
|
101
|
+
const deltaFunctionCall = chatFunctionCallingPart.functionCall;
|
|
102
|
+
if (deltaFunctionCall) {
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
104
|
+
let args = deltaFunctionCall.args?.input ??
|
|
105
|
+
deltaFunctionCall.args;
|
|
106
|
+
try {
|
|
107
|
+
let parsedArgs = JSON.parse(args);
|
|
108
|
+
if (typeof parsedArgs !== 'string') {
|
|
109
|
+
args = parsedArgs;
|
|
110
|
+
}
|
|
111
|
+
parsedArgs = JSON.parse(args);
|
|
112
|
+
if (typeof parsedArgs !== 'string') {
|
|
113
|
+
args = parsedArgs;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (e) { }
|
|
117
|
+
functionCall.args = JSON.stringify(args);
|
|
118
|
+
functionCall.name =
|
|
119
|
+
functionCall.name + (deltaFunctionCall.name ?? '');
|
|
120
|
+
functionCall.arguments = deltaFunctionCall.args;
|
|
121
|
+
}
|
|
90
122
|
}
|
|
91
123
|
try {
|
|
92
|
-
const messageChunk = new
|
|
93
|
-
messageChunk.
|
|
94
|
-
|
|
124
|
+
const messageChunk = new messages_1.AIMessageChunk(content);
|
|
125
|
+
messageChunk.additional_kwargs = {
|
|
126
|
+
function_call: functionCall.name.length > 0
|
|
127
|
+
? {
|
|
128
|
+
name: functionCall.name,
|
|
129
|
+
arguments: functionCall.args,
|
|
130
|
+
args: functionCall.arguments
|
|
131
|
+
}
|
|
132
|
+
: undefined
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
134
|
+
};
|
|
135
|
+
messageChunk.content = content;
|
|
136
|
+
const generationChunk = new outputs_1.ChatGenerationChunk({
|
|
95
137
|
message: messageChunk,
|
|
96
138
|
text: messageChunk.content
|
|
97
139
|
});
|
|
@@ -183,7 +225,6 @@ class GeminiRequester extends api_1.ModelRequester {
|
|
|
183
225
|
}
|
|
184
226
|
}
|
|
185
227
|
const body = JSON.stringify(data);
|
|
186
|
-
// console.log('POST', requestUrl, body)
|
|
187
228
|
return (0, request_1.chatLunaFetch)(requestUrl, {
|
|
188
229
|
body,
|
|
189
230
|
headers: this._buildHeaders(),
|
package/lib/types.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export interface ChatCompletionResponseMessage {
|
|
2
2
|
role: string;
|
|
3
|
-
parts?:
|
|
3
|
+
parts?: ChatPart[];
|
|
4
4
|
}
|
|
5
|
+
export type ChatPart = ChatMessagePart | ChatUploadDataPart | ChatFunctionCallingPart | ChatFunctionResponsePart;
|
|
5
6
|
export type ChatMessagePart = {
|
|
6
7
|
text: string;
|
|
7
8
|
};
|
|
@@ -11,6 +12,18 @@ export type ChatUploadDataPart = {
|
|
|
11
12
|
data?: string;
|
|
12
13
|
};
|
|
13
14
|
};
|
|
15
|
+
export type ChatFunctionCallingPart = {
|
|
16
|
+
functionCall: {
|
|
17
|
+
name: string;
|
|
18
|
+
args?: any;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export type ChatFunctionResponsePart = {
|
|
22
|
+
functionResponse: {
|
|
23
|
+
name: string;
|
|
24
|
+
response: any;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
14
27
|
export interface ChatResponse {
|
|
15
28
|
candidates: {
|
|
16
29
|
content: ChatCompletionResponseMessage;
|
|
@@ -28,9 +41,20 @@ export interface ChatResponse {
|
|
|
28
41
|
}[];
|
|
29
42
|
};
|
|
30
43
|
}
|
|
44
|
+
export interface ChatCompletionFunction {
|
|
45
|
+
name: string;
|
|
46
|
+
description?: string;
|
|
47
|
+
parameters?: {
|
|
48
|
+
[key: string]: any;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export interface ChatCompletionMessageFunctionCall {
|
|
52
|
+
name: string;
|
|
53
|
+
args?: any;
|
|
54
|
+
}
|
|
31
55
|
export interface CreateEmbeddingResponse {
|
|
32
56
|
embedding: {
|
|
33
57
|
values: number[];
|
|
34
58
|
};
|
|
35
59
|
}
|
|
36
|
-
export type ChatCompletionResponseMessageRoleEnum = 'system' | 'model' | 'user';
|
|
60
|
+
export type ChatCompletionResponseMessageRoleEnum = 'system' | 'model' | 'user' | 'function';
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { AIMessageChunk, BaseMessage, ChatMessageChunk, HumanMessageChunk, MessageType, SystemMessageChunk } from 'langchain/
|
|
2
|
-
import { ChatCompletionResponseMessage, ChatCompletionResponseMessageRoleEnum } from './types';
|
|
1
|
+
import { AIMessageChunk, BaseMessage, ChatMessageChunk, HumanMessageChunk, MessageType, SystemMessageChunk } from '@langchain/core/messages';
|
|
2
|
+
import { ChatCompletionFunction, ChatCompletionResponseMessage, ChatCompletionResponseMessageRoleEnum, ChatPart } from './types';
|
|
3
|
+
import { StructuredTool } from '@langchain/core/tools';
|
|
3
4
|
export declare function langchainMessageToGeminiMessage(messages: BaseMessage[], model?: string): Promise<ChatCompletionResponseMessage[]>;
|
|
5
|
+
export declare function partAsType<T extends ChatPart>(part: ChatPart): T;
|
|
6
|
+
export declare function formatToolsToGeminiAITools(tools: StructuredTool[]): ChatCompletionFunction[];
|
|
7
|
+
export declare function formatToolToGeminiAITool(tool: StructuredTool): ChatCompletionFunction;
|
|
4
8
|
export declare function messageTypeToGeminiRole(type: MessageType): ChatCompletionResponseMessageRoleEnum;
|
|
5
9
|
export declare function convertDeltaToMessageChunk(delta: Record<string, any>, defaultRole?: ChatCompletionResponseMessageRoleEnum): HumanMessageChunk | AIMessageChunk | SystemMessageChunk | ChatMessageChunk;
|
package/lib/utils.js
CHANGED
|
@@ -1,10 +1,81 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.convertDeltaToMessageChunk = exports.messageTypeToGeminiRole = exports.langchainMessageToGeminiMessage = void 0;
|
|
4
|
-
|
|
3
|
+
exports.convertDeltaToMessageChunk = exports.messageTypeToGeminiRole = exports.formatToolToGeminiAITool = exports.formatToolsToGeminiAITools = exports.partAsType = exports.langchainMessageToGeminiMessage = void 0;
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
5
|
+
const messages_1 = require("@langchain/core/messages");
|
|
6
|
+
const zod_to_json_schema_1 = require("zod-to-json-schema");
|
|
5
7
|
async function langchainMessageToGeminiMessage(messages, model) {
|
|
6
8
|
const mappedMessage = await Promise.all(messages.map(async (rawMessage) => {
|
|
7
9
|
const role = messageTypeToGeminiRole(rawMessage._getType());
|
|
10
|
+
if (role === 'function' ||
|
|
11
|
+
rawMessage.additional_kwargs?.function_call != null) {
|
|
12
|
+
return {
|
|
13
|
+
role: 'function',
|
|
14
|
+
parts: [
|
|
15
|
+
{
|
|
16
|
+
functionResponse: rawMessage.additional_kwargs?.function_call !=
|
|
17
|
+
null
|
|
18
|
+
? undefined
|
|
19
|
+
: {
|
|
20
|
+
name: rawMessage.name,
|
|
21
|
+
response: {
|
|
22
|
+
name: rawMessage.name,
|
|
23
|
+
content: (() => {
|
|
24
|
+
try {
|
|
25
|
+
const result = JSON.parse(rawMessage.content);
|
|
26
|
+
if (typeof result ===
|
|
27
|
+
'string') {
|
|
28
|
+
return {
|
|
29
|
+
response: result
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
return {
|
|
38
|
+
response: rawMessage.content
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
})()
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
functionCall: rawMessage.additional_kwargs?.function_call !=
|
|
45
|
+
null
|
|
46
|
+
? {
|
|
47
|
+
name: rawMessage.additional_kwargs
|
|
48
|
+
.function_call.name,
|
|
49
|
+
args: (() => {
|
|
50
|
+
try {
|
|
51
|
+
const result = JSON.parse(rawMessage
|
|
52
|
+
.additional_kwargs
|
|
53
|
+
.function_call
|
|
54
|
+
.arguments);
|
|
55
|
+
if (typeof result === 'string') {
|
|
56
|
+
return {
|
|
57
|
+
input: result
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
return {
|
|
66
|
+
input: rawMessage
|
|
67
|
+
.additional_kwargs
|
|
68
|
+
.function_call
|
|
69
|
+
.arguments
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
})()
|
|
73
|
+
}
|
|
74
|
+
: undefined
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
}
|
|
8
79
|
const images = rawMessage.additional_kwargs.images;
|
|
9
80
|
const result = {
|
|
10
81
|
role,
|
|
@@ -49,7 +120,7 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
49
120
|
parts: [{ text: 'Okay, what do I need to do?' }]
|
|
50
121
|
});
|
|
51
122
|
}
|
|
52
|
-
if (result[result.length - 1].role === '
|
|
123
|
+
if (result[result.length - 1].role === 'model') {
|
|
53
124
|
result.push({
|
|
54
125
|
role: 'user',
|
|
55
126
|
parts: [
|
|
@@ -102,6 +173,31 @@ async function langchainMessageToGeminiMessage(messages, model) {
|
|
|
102
173
|
return result;
|
|
103
174
|
}
|
|
104
175
|
exports.langchainMessageToGeminiMessage = langchainMessageToGeminiMessage;
|
|
176
|
+
function partAsType(part) {
|
|
177
|
+
return part;
|
|
178
|
+
}
|
|
179
|
+
exports.partAsType = partAsType;
|
|
180
|
+
function formatToolsToGeminiAITools(tools) {
|
|
181
|
+
if (tools.length < 1) {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
return tools.map(formatToolToGeminiAITool);
|
|
185
|
+
}
|
|
186
|
+
exports.formatToolsToGeminiAITools = formatToolsToGeminiAITools;
|
|
187
|
+
function formatToolToGeminiAITool(tool) {
|
|
188
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
189
|
+
const parameters = (0, zod_to_json_schema_1.zodToJsonSchema)(tool.schema);
|
|
190
|
+
// remove unsupported properties
|
|
191
|
+
delete parameters['$schema'];
|
|
192
|
+
delete parameters['additionalProperties'];
|
|
193
|
+
return {
|
|
194
|
+
name: tool.name,
|
|
195
|
+
description: tool.description,
|
|
196
|
+
// any?
|
|
197
|
+
parameters
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
exports.formatToolToGeminiAITool = formatToolToGeminiAITool;
|
|
105
201
|
function messageTypeToGeminiRole(type) {
|
|
106
202
|
switch (type) {
|
|
107
203
|
case 'system':
|
|
@@ -110,6 +206,8 @@ function messageTypeToGeminiRole(type) {
|
|
|
110
206
|
return 'model';
|
|
111
207
|
case 'human':
|
|
112
208
|
return 'user';
|
|
209
|
+
case 'function':
|
|
210
|
+
return 'function';
|
|
113
211
|
default:
|
|
114
212
|
throw new Error(`Unknown message type: ${type}`);
|
|
115
213
|
}
|
|
@@ -136,16 +234,16 @@ delta, defaultRole) {
|
|
|
136
234
|
additional_kwargs = {};
|
|
137
235
|
}
|
|
138
236
|
if (role === 'user') {
|
|
139
|
-
return new
|
|
237
|
+
return new messages_1.HumanMessageChunk({ content });
|
|
140
238
|
}
|
|
141
239
|
else if (role === 'assistant') {
|
|
142
|
-
return new
|
|
240
|
+
return new messages_1.AIMessageChunk({ content, additional_kwargs });
|
|
143
241
|
}
|
|
144
242
|
else if (role === 'system') {
|
|
145
|
-
return new
|
|
243
|
+
return new messages_1.SystemMessageChunk({ content });
|
|
146
244
|
}
|
|
147
245
|
else {
|
|
148
|
-
return new
|
|
246
|
+
return new messages_1.ChatMessageChunk({ content, role });
|
|
149
247
|
}
|
|
150
248
|
}
|
|
151
249
|
exports.convertDeltaToMessageChunk = convertDeltaToMessageChunk;
|
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.0.0-beta.
|
|
4
|
+
"version": "1.0.0-beta.7",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -38,16 +38,18 @@
|
|
|
38
38
|
"adapter"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
+
"@langchain/core": "^0.1.15",
|
|
41
42
|
"@streamparser/json": "^0.0.19",
|
|
42
|
-
"
|
|
43
|
+
"zod": "^3.22.4",
|
|
44
|
+
"zod-to-json-schema": "^3.22.3"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
45
47
|
"atsc": "^1.2.2",
|
|
46
|
-
"koishi": "^4.16.
|
|
48
|
+
"koishi": "^4.16.4"
|
|
47
49
|
},
|
|
48
50
|
"peerDependencies": {
|
|
49
51
|
"koishi": "^4.16.0",
|
|
50
|
-
"koishi-plugin-chatluna": "^1.0.0-beta.
|
|
52
|
+
"koishi-plugin-chatluna": "^1.0.0-beta.33"
|
|
51
53
|
},
|
|
52
54
|
"koishi": {
|
|
53
55
|
"description": {
|