@chatluna/v1-shared-adapter 1.0.26 → 1.0.28
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 +68 -9
- package/lib/index.mjs +68 -9
- package/lib/utils.d.ts +30 -2
- package/package.json +2 -2
package/lib/index.cjs
CHANGED
|
@@ -28,6 +28,7 @@ __export(index_exports, {
|
|
|
28
28
|
createEmbeddings: () => createEmbeddings,
|
|
29
29
|
createRequestContext: () => createRequestContext,
|
|
30
30
|
expandReasoningEffortModelVariants: () => expandReasoningEffortModelVariants,
|
|
31
|
+
fetchFileLikeUrl: () => fetchFileLikeUrl,
|
|
31
32
|
fetchImageUrl: () => fetchImageUrl,
|
|
32
33
|
formatToolToOpenAITool: () => formatToolToOpenAITool,
|
|
33
34
|
formatToolsToOpenAITools: () => formatToolsToOpenAITools,
|
|
@@ -190,11 +191,10 @@ var import_messages = require("@langchain/core/messages");
|
|
|
190
191
|
var import_zod_to_json_schema = require("zod-to-json-schema");
|
|
191
192
|
var import_string = require("koishi-plugin-chatluna/utils/string");
|
|
192
193
|
var import_types = require("@langchain/core/utils/types");
|
|
193
|
-
async function langchainMessageToOpenAIMessage(messages, plugin, model,
|
|
194
|
+
async function langchainMessageToOpenAIMessage(messages, plugin, model, supportImageInputType, removeSystemMessage) {
|
|
194
195
|
const result = [];
|
|
195
196
|
const normalizedModel = model ? normalizeOpenAIModelName(model) : model;
|
|
196
197
|
const isDeepseekThinkModel = normalizedModel?.includes("deepseek-reasoner");
|
|
197
|
-
console.log(messages);
|
|
198
198
|
for (const rawMessage of messages) {
|
|
199
199
|
const role = messageTypeToOpenAIRole(rawMessage.getType());
|
|
200
200
|
const msg = {
|
|
@@ -225,7 +225,7 @@ async function langchainMessageToOpenAIMessage(messages, plugin, model, supportI
|
|
|
225
225
|
}
|
|
226
226
|
const images = rawMessage.additional_kwargs.images;
|
|
227
227
|
const lowerModel = normalizedModel?.toLowerCase() ?? "";
|
|
228
|
-
if (
|
|
228
|
+
if (images != null && (supportImageInput(lowerModel) || supportImageInputType)) {
|
|
229
229
|
msg.content = [
|
|
230
230
|
{
|
|
231
231
|
type: "text",
|
|
@@ -377,15 +377,73 @@ async function fetchImageUrl(plugin, content) {
|
|
|
377
377
|
}
|
|
378
378
|
const ext = url.match(/\.([^.?#]+)(?:[?#]|$)/)?.[1]?.toLowerCase();
|
|
379
379
|
const imageType = (0, import_string.getImageMimeType)(ext);
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
380
|
+
const controller = new AbortController();
|
|
381
|
+
const timeout = setTimeout(() => controller.abort(), 6e4);
|
|
382
|
+
const response = await plugin.fetch(url, {
|
|
383
|
+
signal: controller.signal
|
|
384
|
+
}).finally(() => {
|
|
385
|
+
clearTimeout(timeout);
|
|
386
|
+
});
|
|
387
|
+
if (!response.ok) {
|
|
388
|
+
throw new Error(`Failed to fetch image: ${response.status}`);
|
|
389
|
+
}
|
|
390
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
386
391
|
return `data:${imageType};base64,${buffer.toString("base64")}`;
|
|
387
392
|
}
|
|
388
393
|
__name(fetchImageUrl, "fetchImageUrl");
|
|
394
|
+
function getFileLikeUrlInfo(content) {
|
|
395
|
+
switch (content.type) {
|
|
396
|
+
case "file_url": {
|
|
397
|
+
const raw = content.file_url;
|
|
398
|
+
return {
|
|
399
|
+
url: typeof raw === "string" ? raw : raw.url,
|
|
400
|
+
mimeType: typeof raw === "string" ? void 0 : raw.mimeType
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
case "audio_url": {
|
|
404
|
+
const raw = content.audio_url;
|
|
405
|
+
return {
|
|
406
|
+
url: typeof raw === "string" ? raw : raw.url,
|
|
407
|
+
mimeType: typeof raw === "string" ? void 0 : raw.mimeType
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
case "video_url": {
|
|
411
|
+
const raw = content.video_url;
|
|
412
|
+
return {
|
|
413
|
+
url: typeof raw === "string" ? raw : raw.url,
|
|
414
|
+
mimeType: typeof raw === "string" ? void 0 : raw.mimeType
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
__name(getFileLikeUrlInfo, "getFileLikeUrlInfo");
|
|
420
|
+
async function fetchFileLikeUrl(plugin, content) {
|
|
421
|
+
const { url, mimeType } = getFileLikeUrlInfo(content);
|
|
422
|
+
const dataUrlMatch = url.match(/^data:([^;,]+);base64,(.+)$/i);
|
|
423
|
+
if (dataUrlMatch) {
|
|
424
|
+
return {
|
|
425
|
+
buffer: Buffer.from(dataUrlMatch[2], "base64"),
|
|
426
|
+
mimeType: dataUrlMatch[1] || mimeType || "application/octet-stream"
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
const controller = new AbortController();
|
|
430
|
+
const timeout = setTimeout(() => controller.abort(), 6e4);
|
|
431
|
+
const response = await plugin.fetch(url, {
|
|
432
|
+
signal: controller.signal
|
|
433
|
+
}).finally(() => {
|
|
434
|
+
clearTimeout(timeout);
|
|
435
|
+
});
|
|
436
|
+
if (!response.ok) {
|
|
437
|
+
throw new Error(`Failed to fetch file: ${response.status}`);
|
|
438
|
+
}
|
|
439
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
440
|
+
const fetchedMimeType = response.headers.get("content-type")?.split(";")[0]?.trim();
|
|
441
|
+
return {
|
|
442
|
+
buffer,
|
|
443
|
+
mimeType: mimeType ?? fetchedMimeType ?? (0, import_string.getMimeTypeFromSource)(url) ?? "application/octet-stream"
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
__name(fetchFileLikeUrl, "fetchFileLikeUrl");
|
|
389
447
|
function messageTypeToOpenAIRole(type) {
|
|
390
448
|
switch (type) {
|
|
391
449
|
case "system":
|
|
@@ -900,6 +958,7 @@ __name(createRequestContext, "createRequestContext");
|
|
|
900
958
|
createEmbeddings,
|
|
901
959
|
createRequestContext,
|
|
902
960
|
expandReasoningEffortModelVariants,
|
|
961
|
+
fetchFileLikeUrl,
|
|
903
962
|
fetchImageUrl,
|
|
904
963
|
formatToolToOpenAITool,
|
|
905
964
|
formatToolsToOpenAITools,
|
package/lib/index.mjs
CHANGED
|
@@ -151,14 +151,14 @@ import {
|
|
|
151
151
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
152
152
|
import {
|
|
153
153
|
getImageMimeType,
|
|
154
|
+
getMimeTypeFromSource,
|
|
154
155
|
isMessageContentImageUrl
|
|
155
156
|
} from "koishi-plugin-chatluna/utils/string";
|
|
156
157
|
import { isZodSchemaV3 } from "@langchain/core/utils/types";
|
|
157
|
-
async function langchainMessageToOpenAIMessage(messages, plugin, model,
|
|
158
|
+
async function langchainMessageToOpenAIMessage(messages, plugin, model, supportImageInputType, removeSystemMessage) {
|
|
158
159
|
const result = [];
|
|
159
160
|
const normalizedModel = model ? normalizeOpenAIModelName(model) : model;
|
|
160
161
|
const isDeepseekThinkModel = normalizedModel?.includes("deepseek-reasoner");
|
|
161
|
-
console.log(messages);
|
|
162
162
|
for (const rawMessage of messages) {
|
|
163
163
|
const role = messageTypeToOpenAIRole(rawMessage.getType());
|
|
164
164
|
const msg = {
|
|
@@ -189,7 +189,7 @@ async function langchainMessageToOpenAIMessage(messages, plugin, model, supportI
|
|
|
189
189
|
}
|
|
190
190
|
const images = rawMessage.additional_kwargs.images;
|
|
191
191
|
const lowerModel = normalizedModel?.toLowerCase() ?? "";
|
|
192
|
-
if (
|
|
192
|
+
if (images != null && (supportImageInput(lowerModel) || supportImageInputType)) {
|
|
193
193
|
msg.content = [
|
|
194
194
|
{
|
|
195
195
|
type: "text",
|
|
@@ -341,15 +341,73 @@ async function fetchImageUrl(plugin, content) {
|
|
|
341
341
|
}
|
|
342
342
|
const ext = url.match(/\.([^.?#]+)(?:[?#]|$)/)?.[1]?.toLowerCase();
|
|
343
343
|
const imageType = getImageMimeType(ext);
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
344
|
+
const controller = new AbortController();
|
|
345
|
+
const timeout = setTimeout(() => controller.abort(), 6e4);
|
|
346
|
+
const response = await plugin.fetch(url, {
|
|
347
|
+
signal: controller.signal
|
|
348
|
+
}).finally(() => {
|
|
349
|
+
clearTimeout(timeout);
|
|
350
|
+
});
|
|
351
|
+
if (!response.ok) {
|
|
352
|
+
throw new Error(`Failed to fetch image: ${response.status}`);
|
|
353
|
+
}
|
|
354
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
350
355
|
return `data:${imageType};base64,${buffer.toString("base64")}`;
|
|
351
356
|
}
|
|
352
357
|
__name(fetchImageUrl, "fetchImageUrl");
|
|
358
|
+
function getFileLikeUrlInfo(content) {
|
|
359
|
+
switch (content.type) {
|
|
360
|
+
case "file_url": {
|
|
361
|
+
const raw = content.file_url;
|
|
362
|
+
return {
|
|
363
|
+
url: typeof raw === "string" ? raw : raw.url,
|
|
364
|
+
mimeType: typeof raw === "string" ? void 0 : raw.mimeType
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
case "audio_url": {
|
|
368
|
+
const raw = content.audio_url;
|
|
369
|
+
return {
|
|
370
|
+
url: typeof raw === "string" ? raw : raw.url,
|
|
371
|
+
mimeType: typeof raw === "string" ? void 0 : raw.mimeType
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
case "video_url": {
|
|
375
|
+
const raw = content.video_url;
|
|
376
|
+
return {
|
|
377
|
+
url: typeof raw === "string" ? raw : raw.url,
|
|
378
|
+
mimeType: typeof raw === "string" ? void 0 : raw.mimeType
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
__name(getFileLikeUrlInfo, "getFileLikeUrlInfo");
|
|
384
|
+
async function fetchFileLikeUrl(plugin, content) {
|
|
385
|
+
const { url, mimeType } = getFileLikeUrlInfo(content);
|
|
386
|
+
const dataUrlMatch = url.match(/^data:([^;,]+);base64,(.+)$/i);
|
|
387
|
+
if (dataUrlMatch) {
|
|
388
|
+
return {
|
|
389
|
+
buffer: Buffer.from(dataUrlMatch[2], "base64"),
|
|
390
|
+
mimeType: dataUrlMatch[1] || mimeType || "application/octet-stream"
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
const controller = new AbortController();
|
|
394
|
+
const timeout = setTimeout(() => controller.abort(), 6e4);
|
|
395
|
+
const response = await plugin.fetch(url, {
|
|
396
|
+
signal: controller.signal
|
|
397
|
+
}).finally(() => {
|
|
398
|
+
clearTimeout(timeout);
|
|
399
|
+
});
|
|
400
|
+
if (!response.ok) {
|
|
401
|
+
throw new Error(`Failed to fetch file: ${response.status}`);
|
|
402
|
+
}
|
|
403
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
404
|
+
const fetchedMimeType = response.headers.get("content-type")?.split(";")[0]?.trim();
|
|
405
|
+
return {
|
|
406
|
+
buffer,
|
|
407
|
+
mimeType: mimeType ?? fetchedMimeType ?? getMimeTypeFromSource(url) ?? "application/octet-stream"
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
__name(fetchFileLikeUrl, "fetchFileLikeUrl");
|
|
353
411
|
function messageTypeToOpenAIRole(type) {
|
|
354
412
|
switch (type) {
|
|
355
413
|
case "system":
|
|
@@ -863,6 +921,7 @@ export {
|
|
|
863
921
|
createEmbeddings,
|
|
864
922
|
createRequestContext,
|
|
865
923
|
expandReasoningEffortModelVariants,
|
|
924
|
+
fetchFileLikeUrl,
|
|
866
925
|
fetchImageUrl,
|
|
867
926
|
formatToolToOpenAITool,
|
|
868
927
|
formatToolsToOpenAITools,
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,15 +1,43 @@
|
|
|
1
|
-
import { AIMessageChunk, BaseMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, MessageContentImageUrl, MessageType, SystemMessageChunk, ToolMessageChunk } from '@langchain/core/messages';
|
|
1
|
+
import { AIMessageChunk, BaseMessage, ChatMessageChunk, FunctionMessageChunk, HumanMessageChunk, MessageContentComplex, MessageContentImageUrl, MessageType, SystemMessageChunk, ToolMessageChunk } from '@langchain/core/messages';
|
|
2
2
|
import { StructuredTool } from '@langchain/core/tools';
|
|
3
3
|
import { JsonSchema7Type } from 'zod-to-json-schema';
|
|
4
4
|
import { ChatCompletionResponseMessage, ChatCompletionResponseMessageRoleEnum, ChatCompletionTool } from './types';
|
|
5
5
|
import { ChatLunaPlugin } from 'koishi-plugin-chatluna/services/chat';
|
|
6
|
-
export declare function langchainMessageToOpenAIMessage(messages: BaseMessage[], plugin: ChatLunaPlugin, model?: string,
|
|
6
|
+
export declare function langchainMessageToOpenAIMessage(messages: BaseMessage[], plugin: ChatLunaPlugin, model?: string, supportImageInputType?: boolean, removeSystemMessage?: boolean): Promise<ChatCompletionResponseMessage[]>;
|
|
7
7
|
export declare function processDeepSeekThinkMessages(convertedMessages: ChatCompletionResponseMessage[], originalMessages: BaseMessage[]): ChatCompletionResponseMessage[];
|
|
8
8
|
export declare function transformSystemMessages(messages: ChatCompletionResponseMessage[]): ChatCompletionResponseMessage[];
|
|
9
9
|
export declare function fetchImageUrl(plugin: ChatLunaPlugin, content: MessageContentImageUrl): Promise<string>;
|
|
10
|
+
type MessageContentFileLike = MessageContentComplex & ({
|
|
11
|
+
type: 'file_url';
|
|
12
|
+
file_url: string | {
|
|
13
|
+
url: string;
|
|
14
|
+
mimeType?: string;
|
|
15
|
+
};
|
|
16
|
+
} | {
|
|
17
|
+
type: 'audio_url';
|
|
18
|
+
audio_url: string | {
|
|
19
|
+
url: string;
|
|
20
|
+
mimeType?: string;
|
|
21
|
+
};
|
|
22
|
+
} | {
|
|
23
|
+
type: 'video_url';
|
|
24
|
+
video_url: string | {
|
|
25
|
+
url: string;
|
|
26
|
+
mimeType?: string;
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Fetch file/audio/video content and return decoded bytes.
|
|
31
|
+
* If the source is a base64 data URL, it is decoded directly.
|
|
32
|
+
*/
|
|
33
|
+
export declare function fetchFileLikeUrl(plugin: ChatLunaPlugin, content: MessageContentFileLike): Promise<{
|
|
34
|
+
buffer: Buffer<ArrayBuffer>;
|
|
35
|
+
mimeType: string;
|
|
36
|
+
}>;
|
|
10
37
|
export declare function messageTypeToOpenAIRole(type: MessageType): ChatCompletionResponseMessageRoleEnum;
|
|
11
38
|
export declare function formatToolsToOpenAITools(tools: StructuredTool[], includeGoogleSearch: boolean): ChatCompletionTool[];
|
|
12
39
|
export declare function formatToolToOpenAITool(tool: StructuredTool): ChatCompletionTool;
|
|
13
40
|
export declare function removeAdditionalProperties(schema: JsonSchema7Type): JsonSchema7Type;
|
|
14
41
|
export declare function convertMessageToMessageChunk(message: ChatCompletionResponseMessage): HumanMessageChunk | AIMessageChunk | SystemMessageChunk | FunctionMessageChunk | ToolMessageChunk | ChatMessageChunk;
|
|
15
42
|
export declare function convertDeltaToMessageChunk(delta: Record<string, any>, defaultRole?: ChatCompletionResponseMessageRoleEnum): HumanMessageChunk | AIMessageChunk | SystemMessageChunk | FunctionMessageChunk | ToolMessageChunk | ChatMessageChunk;
|
|
43
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatluna/v1-shared-adapter",
|
|
3
3
|
"description": "chatluna shared adapter",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.28",
|
|
5
5
|
"main": "lib/index.cjs",
|
|
6
6
|
"module": "lib/index.mjs",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
@@ -70,6 +70,6 @@
|
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
72
|
"koishi": "^4.18.9",
|
|
73
|
-
"koishi-plugin-chatluna": "^1.3.
|
|
73
|
+
"koishi-plugin-chatluna": "^1.3.23"
|
|
74
74
|
}
|
|
75
75
|
}
|