@chatluna/v1-shared-adapter 1.0.27 → 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 -8
- package/lib/index.mjs +68 -8
- 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,7 +191,7 @@ 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");
|
|
@@ -224,7 +225,7 @@ async function langchainMessageToOpenAIMessage(messages, plugin, model, supportI
|
|
|
224
225
|
}
|
|
225
226
|
const images = rawMessage.additional_kwargs.images;
|
|
226
227
|
const lowerModel = normalizedModel?.toLowerCase() ?? "";
|
|
227
|
-
if (
|
|
228
|
+
if (images != null && (supportImageInput(lowerModel) || supportImageInputType)) {
|
|
228
229
|
msg.content = [
|
|
229
230
|
{
|
|
230
231
|
type: "text",
|
|
@@ -376,15 +377,73 @@ async function fetchImageUrl(plugin, content) {
|
|
|
376
377
|
}
|
|
377
378
|
const ext = url.match(/\.([^.?#]+)(?:[?#]|$)/)?.[1]?.toLowerCase();
|
|
378
379
|
const imageType = (0, import_string.getImageMimeType)(ext);
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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());
|
|
385
391
|
return `data:${imageType};base64,${buffer.toString("base64")}`;
|
|
386
392
|
}
|
|
387
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");
|
|
388
447
|
function messageTypeToOpenAIRole(type) {
|
|
389
448
|
switch (type) {
|
|
390
449
|
case "system":
|
|
@@ -899,6 +958,7 @@ __name(createRequestContext, "createRequestContext");
|
|
|
899
958
|
createEmbeddings,
|
|
900
959
|
createRequestContext,
|
|
901
960
|
expandReasoningEffortModelVariants,
|
|
961
|
+
fetchFileLikeUrl,
|
|
902
962
|
fetchImageUrl,
|
|
903
963
|
formatToolToOpenAITool,
|
|
904
964
|
formatToolsToOpenAITools,
|
package/lib/index.mjs
CHANGED
|
@@ -151,10 +151,11 @@ 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");
|
|
@@ -188,7 +189,7 @@ async function langchainMessageToOpenAIMessage(messages, plugin, model, supportI
|
|
|
188
189
|
}
|
|
189
190
|
const images = rawMessage.additional_kwargs.images;
|
|
190
191
|
const lowerModel = normalizedModel?.toLowerCase() ?? "";
|
|
191
|
-
if (
|
|
192
|
+
if (images != null && (supportImageInput(lowerModel) || supportImageInputType)) {
|
|
192
193
|
msg.content = [
|
|
193
194
|
{
|
|
194
195
|
type: "text",
|
|
@@ -340,15 +341,73 @@ async function fetchImageUrl(plugin, content) {
|
|
|
340
341
|
}
|
|
341
342
|
const ext = url.match(/\.([^.?#]+)(?:[?#]|$)/)?.[1]?.toLowerCase();
|
|
342
343
|
const imageType = getImageMimeType(ext);
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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());
|
|
349
355
|
return `data:${imageType};base64,${buffer.toString("base64")}`;
|
|
350
356
|
}
|
|
351
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");
|
|
352
411
|
function messageTypeToOpenAIRole(type) {
|
|
353
412
|
switch (type) {
|
|
354
413
|
case "system":
|
|
@@ -862,6 +921,7 @@ export {
|
|
|
862
921
|
createEmbeddings,
|
|
863
922
|
createRequestContext,
|
|
864
923
|
expandReasoningEffortModelVariants,
|
|
924
|
+
fetchFileLikeUrl,
|
|
865
925
|
fetchImageUrl,
|
|
866
926
|
formatToolToOpenAITool,
|
|
867
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
|
}
|