koishi-plugin-chatluna 1.3.7 → 1.3.8
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 +202 -165
- package/lib/index.mjs +202 -165
- package/lib/llm-core/agent/openai/index.d.ts +1 -1
- package/lib/llm-core/agent/openai/output_parser.d.ts +1 -1
- package/package.json +9 -8
package/lib/index.cjs
CHANGED
|
@@ -3249,7 +3249,7 @@ __name(apply24, "apply");
|
|
|
3249
3249
|
var import_logger3 = require("koishi-plugin-chatluna/utils/logger");
|
|
3250
3250
|
var import_crypto4 = require("crypto");
|
|
3251
3251
|
var logger6;
|
|
3252
|
-
var
|
|
3252
|
+
var queues = /* @__PURE__ */ new Map();
|
|
3253
3253
|
function apply25(ctx, config, chain) {
|
|
3254
3254
|
logger6 = (0, import_logger3.createLogger)(ctx);
|
|
3255
3255
|
chain.middleware("message_delay", async (session, context) => {
|
|
@@ -3261,203 +3261,162 @@ function apply25(ctx, config, chain) {
|
|
|
3261
3261
|
const conversationId = room.conversationId;
|
|
3262
3262
|
const userName = inputMessage.name || "unknown";
|
|
3263
3263
|
const messageId = context.options.messageId;
|
|
3264
|
-
const
|
|
3265
|
-
|
|
3264
|
+
const conversation = queues.get(conversationId) ?? {
|
|
3265
|
+
turns: [],
|
|
3266
|
+
inFlight: false
|
|
3267
|
+
};
|
|
3268
|
+
queues.set(conversationId, conversation);
|
|
3269
|
+
const tailTurn = conversation.turns[conversation.turns.length - 1];
|
|
3270
|
+
let turn;
|
|
3271
|
+
if (tailTurn && tailTurn.state !== "processing" && tailTurn.userName === userName) {
|
|
3272
|
+
turn = tailTurn;
|
|
3266
3273
|
logger6.debug(
|
|
3267
|
-
`
|
|
3274
|
+
`Joining turn for ${conversationId}, messageId: ${messageId}, user: ${userName}, total: ${turn.messages.length + 1}`
|
|
3268
3275
|
);
|
|
3269
|
-
|
|
3270
|
-
|
|
3276
|
+
} else {
|
|
3277
|
+
const state = conversation.turns.length === 0 && config.messageQueueDelay > 0 ? "collecting" : "waiting";
|
|
3278
|
+
turn = {
|
|
3279
|
+
messages: [],
|
|
3271
3280
|
userName,
|
|
3272
|
-
|
|
3273
|
-
collectWaiters: [],
|
|
3274
|
-
state: config.messageQueueDelay > 0 ? "collecting" : "processing"
|
|
3281
|
+
state
|
|
3275
3282
|
};
|
|
3276
|
-
|
|
3277
|
-
if (config.messageQueueDelay > 0) {
|
|
3278
|
-
resetBatchTimeout(ctx, config, newBatch, conversationId);
|
|
3279
|
-
return await awaitCollectingBatch(newBatch, context);
|
|
3280
|
-
}
|
|
3281
|
-
newBatch.messages = [];
|
|
3282
|
-
return 2 /* CONTINUE */;
|
|
3283
|
-
}
|
|
3284
|
-
if (batch.userName !== userName) {
|
|
3285
|
-
logger6.debug(
|
|
3286
|
-
`User mismatch for ${conversationId}, messageId: ${messageId}, waiting for batch completion`
|
|
3287
|
-
);
|
|
3288
|
-
return await waitForBatchCompletion(
|
|
3289
|
-
batch,
|
|
3290
|
-
conversationId,
|
|
3291
|
-
inputMessage,
|
|
3292
|
-
userName,
|
|
3293
|
-
context
|
|
3294
|
-
);
|
|
3295
|
-
}
|
|
3296
|
-
if (batch.state === "collecting") {
|
|
3283
|
+
conversation.turns.push(turn);
|
|
3297
3284
|
logger6.debug(
|
|
3298
|
-
`
|
|
3285
|
+
`Creating new turn for ${conversationId}, messageId: ${messageId}, user: ${userName}, queue: ${conversation.turns.length}`
|
|
3299
3286
|
);
|
|
3300
|
-
batch.messages.push(inputMessage);
|
|
3301
|
-
if (config.messageQueueDelay > 0) {
|
|
3302
|
-
resetBatchTimeout(ctx, config, batch, conversationId);
|
|
3303
|
-
}
|
|
3304
|
-
return await awaitCollectingBatch(batch, context);
|
|
3305
3287
|
}
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
)
|
|
3309
|
-
|
|
3310
|
-
if (status === 1 /* STOP */) {
|
|
3311
|
-
return status;
|
|
3288
|
+
turn.messages.push(inputMessage);
|
|
3289
|
+
const statusPromise = awaitTurnStart(turn, context);
|
|
3290
|
+
if (turn.state === "collecting") {
|
|
3291
|
+
resetTurnTimeout(ctx, config, conversationId, turn);
|
|
3312
3292
|
}
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
);
|
|
3316
|
-
return interruptAndMerge(batch, context);
|
|
3293
|
+
tryStartHeadTurn(conversationId, conversation);
|
|
3294
|
+
return await statusPromise;
|
|
3317
3295
|
}).after("check_room").after("read_chat_message").before("lifecycle-handle_command");
|
|
3318
|
-
const
|
|
3319
|
-
const
|
|
3320
|
-
if (
|
|
3296
|
+
const completeTurn = /* @__PURE__ */ __name(async (conversationId) => {
|
|
3297
|
+
const conversation = queues.get(conversationId);
|
|
3298
|
+
if (!conversation) {
|
|
3299
|
+
return;
|
|
3300
|
+
}
|
|
3301
|
+
const current = conversation.turns.shift();
|
|
3302
|
+
conversation.inFlight = false;
|
|
3303
|
+
if (current?.timeout) {
|
|
3304
|
+
current.timeout();
|
|
3305
|
+
}
|
|
3306
|
+
if (current?.starter) {
|
|
3307
|
+
current.starter.resolve(1 /* STOP */);
|
|
3308
|
+
current.starter = void 0;
|
|
3309
|
+
}
|
|
3310
|
+
if (conversation.turns.length === 0) {
|
|
3311
|
+
queues.delete(conversationId);
|
|
3312
|
+
return;
|
|
3313
|
+
}
|
|
3314
|
+
tryStartHeadTurn(conversationId, conversation);
|
|
3315
|
+
if (current) {
|
|
3321
3316
|
logger6.debug(
|
|
3322
|
-
`Completing
|
|
3323
|
-
);
|
|
3324
|
-
if (batch.timeout) {
|
|
3325
|
-
batch.timeout();
|
|
3326
|
-
}
|
|
3327
|
-
const waiters = batch.resolveWaiters;
|
|
3328
|
-
batch.resolveWaiters = [];
|
|
3329
|
-
waiters.forEach(
|
|
3330
|
-
(resolve) => resolve(2 /* CONTINUE */)
|
|
3317
|
+
`Completing turn for ${conversationId}, remaining: ${conversation.turns.length}`
|
|
3331
3318
|
);
|
|
3332
|
-
} else if (batch) {
|
|
3333
|
-
logger6.debug(`Cleaning up batch for ${conversationId}`);
|
|
3334
|
-
if (batch.timeout) {
|
|
3335
|
-
batch.timeout();
|
|
3336
|
-
}
|
|
3337
|
-
batches.delete(conversationId);
|
|
3338
3319
|
}
|
|
3339
|
-
}, "
|
|
3340
|
-
ctx.on(
|
|
3341
|
-
"chatluna/after-chat",
|
|
3342
|
-
async (conversationId) => await completeBatch(conversationId)
|
|
3343
|
-
);
|
|
3320
|
+
}, "completeTurn");
|
|
3321
|
+
ctx.on("chatluna/after-chat", completeTurn);
|
|
3344
3322
|
ctx.on(
|
|
3345
3323
|
"chatluna/after-chat-error",
|
|
3346
|
-
|
|
3324
|
+
(_, conversationId) => completeTurn(conversationId)
|
|
3347
3325
|
);
|
|
3348
3326
|
ctx.on("chatluna/clear-chat-history", async (conversationId) => {
|
|
3349
|
-
const
|
|
3350
|
-
if (
|
|
3327
|
+
const conversation = queues.get(conversationId);
|
|
3328
|
+
if (conversation) {
|
|
3329
|
+
const stoppedWaiters = conversation.turns.filter(
|
|
3330
|
+
(turn) => !!turn.starter
|
|
3331
|
+
).length;
|
|
3351
3332
|
logger6.debug(
|
|
3352
|
-
`Clearing chat history for ${conversationId}, stopping ${
|
|
3333
|
+
`Clearing chat history for ${conversationId}, stopping ${stoppedWaiters} waiters`
|
|
3353
3334
|
);
|
|
3354
|
-
|
|
3355
|
-
|
|
3335
|
+
for (const turn of conversation.turns) {
|
|
3336
|
+
if (turn.timeout) {
|
|
3337
|
+
turn.timeout();
|
|
3338
|
+
turn.timeout = void 0;
|
|
3339
|
+
}
|
|
3340
|
+
if (turn.starter) {
|
|
3341
|
+
turn.starter.resolve(1 /* STOP */);
|
|
3342
|
+
turn.starter = void 0;
|
|
3343
|
+
}
|
|
3356
3344
|
}
|
|
3357
|
-
|
|
3358
|
-
(resolve) => resolve(1 /* STOP */)
|
|
3359
|
-
);
|
|
3360
|
-
batch.collectWaiters.forEach(
|
|
3361
|
-
(resolve) => resolve(1 /* STOP */)
|
|
3362
|
-
);
|
|
3363
|
-
batches.delete(conversationId);
|
|
3345
|
+
queues.delete(conversationId);
|
|
3364
3346
|
}
|
|
3365
3347
|
});
|
|
3366
3348
|
}
|
|
3367
3349
|
__name(apply25, "apply");
|
|
3368
|
-
function
|
|
3369
|
-
if (
|
|
3370
|
-
|
|
3350
|
+
function awaitTurnStart(turn, context) {
|
|
3351
|
+
if (turn.starter) {
|
|
3352
|
+
turn.starter.resolve(1 /* STOP */);
|
|
3353
|
+
turn.starter = void 0;
|
|
3371
3354
|
}
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
batch.state = "processing";
|
|
3375
|
-
return 2 /* CONTINUE */;
|
|
3376
|
-
}
|
|
3377
|
-
__name(interruptAndMerge, "interruptAndMerge");
|
|
3378
|
-
async function awaitCollectingBatch(batch, context) {
|
|
3379
|
-
resolveCollectWaiters(batch, 1 /* STOP */);
|
|
3380
|
-
return await new Promise((resolve) => {
|
|
3381
|
-
batch.collectWaiters.push((status) => {
|
|
3382
|
-
if (status === 1 /* STOP */) {
|
|
3383
|
-
resolve(1 /* STOP */);
|
|
3384
|
-
return;
|
|
3385
|
-
}
|
|
3386
|
-
context.options.inputMessage = mergeMessages(batch.messages);
|
|
3387
|
-
batch.messages = [];
|
|
3388
|
-
batch.state = "processing";
|
|
3389
|
-
resolve(2 /* CONTINUE */);
|
|
3390
|
-
});
|
|
3355
|
+
return new Promise((resolve) => {
|
|
3356
|
+
turn.starter = { resolve, context };
|
|
3391
3357
|
});
|
|
3392
3358
|
}
|
|
3393
|
-
__name(
|
|
3394
|
-
function
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
waiters.forEach((resolve) => resolve(status));
|
|
3398
|
-
}
|
|
3399
|
-
__name(resolveCollectWaiters, "resolveCollectWaiters");
|
|
3400
|
-
function resetBatchTimeout(ctx, config, batch, conversationId) {
|
|
3401
|
-
if (batch.timeout) {
|
|
3402
|
-
batch.timeout();
|
|
3359
|
+
__name(awaitTurnStart, "awaitTurnStart");
|
|
3360
|
+
function resetTurnTimeout(ctx, config, conversationId, turn) {
|
|
3361
|
+
if (turn.timeout) {
|
|
3362
|
+
turn.timeout();
|
|
3403
3363
|
}
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
`Delay timeout (${config.messageQueueDelay}s) for ${conversationId}, processing batch with ${batch.messages.length} messages`
|
|
3409
|
-
);
|
|
3410
|
-
batch.timeout = void 0;
|
|
3411
|
-
resolveCollectWaiters(batch, 2 /* CONTINUE */);
|
|
3364
|
+
turn.timeout = ctx.setTimeout(() => {
|
|
3365
|
+
const conversation = queues.get(conversationId);
|
|
3366
|
+
if (!conversation || conversation.turns[0] !== turn) {
|
|
3367
|
+
return;
|
|
3412
3368
|
}
|
|
3369
|
+
turn.state = "waiting";
|
|
3370
|
+
turn.timeout = void 0;
|
|
3371
|
+
if (conversation.inFlight) {
|
|
3372
|
+
return;
|
|
3373
|
+
}
|
|
3374
|
+
logger6.debug(
|
|
3375
|
+
// eslint-disable-next-line max-len
|
|
3376
|
+
`Delay timeout (${config.messageQueueDelay}s) for ${conversationId}, starting turn with ${turn.messages.length} messages`
|
|
3377
|
+
);
|
|
3378
|
+
startHeadTurn(conversationId, conversation, turn);
|
|
3413
3379
|
}, config.messageQueueDelay * 1e3);
|
|
3414
3380
|
}
|
|
3415
|
-
__name(
|
|
3416
|
-
|
|
3417
|
-
if (
|
|
3418
|
-
|
|
3419
|
-
} else {
|
|
3420
|
-
batch.messages.push(message);
|
|
3381
|
+
__name(resetTurnTimeout, "resetTurnTimeout");
|
|
3382
|
+
function tryStartHeadTurn(conversationId, conversation) {
|
|
3383
|
+
if (conversation.inFlight) {
|
|
3384
|
+
return;
|
|
3421
3385
|
}
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
}
|
|
3386
|
+
const head = conversation.turns[0];
|
|
3387
|
+
if (!head) {
|
|
3388
|
+
queues.delete(conversationId);
|
|
3389
|
+
return;
|
|
3390
|
+
}
|
|
3391
|
+
if (head.state === "collecting") {
|
|
3392
|
+
return;
|
|
3393
|
+
}
|
|
3394
|
+
startHeadTurn(conversationId, conversation, head);
|
|
3427
3395
|
}
|
|
3428
|
-
__name(
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
batches.delete(conversationId);
|
|
3451
|
-
resolve(2 /* CONTINUE */);
|
|
3452
|
-
}
|
|
3453
|
-
],
|
|
3454
|
-
collectWaiters: [],
|
|
3455
|
-
state: "processing"
|
|
3456
|
-
});
|
|
3457
|
-
});
|
|
3458
|
-
});
|
|
3396
|
+
__name(tryStartHeadTurn, "tryStartHeadTurn");
|
|
3397
|
+
function startHeadTurn(conversationId, conversation, head) {
|
|
3398
|
+
if (conversation.inFlight) {
|
|
3399
|
+
return;
|
|
3400
|
+
}
|
|
3401
|
+
if (conversation.turns[0] !== head) {
|
|
3402
|
+
return;
|
|
3403
|
+
}
|
|
3404
|
+
if (!head.starter) {
|
|
3405
|
+
return;
|
|
3406
|
+
}
|
|
3407
|
+
if (head.timeout) {
|
|
3408
|
+
head.timeout();
|
|
3409
|
+
head.timeout = void 0;
|
|
3410
|
+
}
|
|
3411
|
+
const starter = head.starter;
|
|
3412
|
+
head.starter = void 0;
|
|
3413
|
+
conversation.inFlight = true;
|
|
3414
|
+
head.state = "processing";
|
|
3415
|
+
starter.context.options.inputMessage = mergeMessages(head.messages);
|
|
3416
|
+
head.messages = [];
|
|
3417
|
+
starter.resolve(2 /* CONTINUE */);
|
|
3459
3418
|
}
|
|
3460
|
-
__name(
|
|
3419
|
+
__name(startHeadTurn, "startHeadTurn");
|
|
3461
3420
|
function mergeMessages(messages) {
|
|
3462
3421
|
if (messages.length === 1) return messages[0];
|
|
3463
3422
|
const base = messages[0];
|
|
@@ -3627,8 +3586,86 @@ function apply26(ctx, config, chain) {
|
|
|
3627
3586
|
)
|
|
3628
3587
|
);
|
|
3629
3588
|
});
|
|
3589
|
+
ctx.inject(["chatluna_storage"], (ctx2) => {
|
|
3590
|
+
logger7.debug("chatluna_storage service loaded.");
|
|
3591
|
+
ctx2.effect(
|
|
3592
|
+
() => ctx2.chatluna.messageTransformer.intercept(
|
|
3593
|
+
"file",
|
|
3594
|
+
async (session, element, message) => {
|
|
3595
|
+
const fileName = element.attrs["file"] ?? element.attrs["name"];
|
|
3596
|
+
const src = element.attrs["src"];
|
|
3597
|
+
let buffer;
|
|
3598
|
+
if (src.startsWith("http")) {
|
|
3599
|
+
buffer = await readFile(ctx2, src);
|
|
3600
|
+
} else {
|
|
3601
|
+
buffer = await readPlatformFile(ctx2, session, element);
|
|
3602
|
+
}
|
|
3603
|
+
if (!buffer?.buffer) {
|
|
3604
|
+
logger7.warn(
|
|
3605
|
+
`Failed to read file for element: ${element.toString()}`
|
|
3606
|
+
);
|
|
3607
|
+
return;
|
|
3608
|
+
}
|
|
3609
|
+
const file = await ctx2.chatluna_storage.createTempFile(
|
|
3610
|
+
buffer.buffer,
|
|
3611
|
+
fileName
|
|
3612
|
+
);
|
|
3613
|
+
addMessageContent(message, `File: ${file.name} ${file.url}`);
|
|
3614
|
+
}
|
|
3615
|
+
)
|
|
3616
|
+
);
|
|
3617
|
+
});
|
|
3630
3618
|
}
|
|
3631
3619
|
__name(apply26, "apply");
|
|
3620
|
+
async function readPlatformFile(ctx, session, element) {
|
|
3621
|
+
const fileId = element.attrs["fileId"];
|
|
3622
|
+
let fileUrl;
|
|
3623
|
+
if (session.platform === "onebot") {
|
|
3624
|
+
const bot = session.bot;
|
|
3625
|
+
if (session.isDirect) {
|
|
3626
|
+
fileUrl = await bot.internal.getPrivateFileUrl(
|
|
3627
|
+
session.userId,
|
|
3628
|
+
fileId
|
|
3629
|
+
);
|
|
3630
|
+
} else {
|
|
3631
|
+
fileUrl = await bot.internal.getGroupFileUrl(
|
|
3632
|
+
session.guildId,
|
|
3633
|
+
fileId,
|
|
3634
|
+
element["busId"]
|
|
3635
|
+
);
|
|
3636
|
+
}
|
|
3637
|
+
}
|
|
3638
|
+
if (!fileUrl) {
|
|
3639
|
+
logger7.warn(`Failed to get file URL for element: ${element.toString()}`);
|
|
3640
|
+
return;
|
|
3641
|
+
}
|
|
3642
|
+
return await readFile(ctx, fileUrl);
|
|
3643
|
+
}
|
|
3644
|
+
__name(readPlatformFile, "readPlatformFile");
|
|
3645
|
+
async function readFile(ctx, url) {
|
|
3646
|
+
try {
|
|
3647
|
+
const response = await ctx.http(url, {
|
|
3648
|
+
responseType: "arraybuffer",
|
|
3649
|
+
method: "get",
|
|
3650
|
+
headers: {
|
|
3651
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
|
|
3652
|
+
}
|
|
3653
|
+
});
|
|
3654
|
+
const buffer = Buffer.from(response.data);
|
|
3655
|
+
const base64 = buffer.toString("base64");
|
|
3656
|
+
return {
|
|
3657
|
+
base64Source: base64,
|
|
3658
|
+
buffer
|
|
3659
|
+
};
|
|
3660
|
+
} catch (error) {
|
|
3661
|
+
logger7.error(`Failed to read file from ${url}:`, error);
|
|
3662
|
+
return {
|
|
3663
|
+
base64Source: null,
|
|
3664
|
+
buffer: null
|
|
3665
|
+
};
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
__name(readFile, "readFile");
|
|
3632
3669
|
async function readImage(ctx, url) {
|
|
3633
3670
|
if (url.startsWith("data:image") && url.includes("base64")) {
|
|
3634
3671
|
const buffer = Buffer.from(url.split(",")[1], "base64");
|
package/lib/index.mjs
CHANGED
|
@@ -3244,7 +3244,7 @@ __name(apply24, "apply");
|
|
|
3244
3244
|
import { createLogger as createLogger3 } from "koishi-plugin-chatluna/utils/logger";
|
|
3245
3245
|
import { randomUUID } from "crypto";
|
|
3246
3246
|
var logger6;
|
|
3247
|
-
var
|
|
3247
|
+
var queues = /* @__PURE__ */ new Map();
|
|
3248
3248
|
function apply25(ctx, config, chain) {
|
|
3249
3249
|
logger6 = createLogger3(ctx);
|
|
3250
3250
|
chain.middleware("message_delay", async (session, context) => {
|
|
@@ -3256,203 +3256,162 @@ function apply25(ctx, config, chain) {
|
|
|
3256
3256
|
const conversationId = room.conversationId;
|
|
3257
3257
|
const userName = inputMessage.name || "unknown";
|
|
3258
3258
|
const messageId = context.options.messageId;
|
|
3259
|
-
const
|
|
3260
|
-
|
|
3259
|
+
const conversation = queues.get(conversationId) ?? {
|
|
3260
|
+
turns: [],
|
|
3261
|
+
inFlight: false
|
|
3262
|
+
};
|
|
3263
|
+
queues.set(conversationId, conversation);
|
|
3264
|
+
const tailTurn = conversation.turns[conversation.turns.length - 1];
|
|
3265
|
+
let turn;
|
|
3266
|
+
if (tailTurn && tailTurn.state !== "processing" && tailTurn.userName === userName) {
|
|
3267
|
+
turn = tailTurn;
|
|
3261
3268
|
logger6.debug(
|
|
3262
|
-
`
|
|
3269
|
+
`Joining turn for ${conversationId}, messageId: ${messageId}, user: ${userName}, total: ${turn.messages.length + 1}`
|
|
3263
3270
|
);
|
|
3264
|
-
|
|
3265
|
-
|
|
3271
|
+
} else {
|
|
3272
|
+
const state = conversation.turns.length === 0 && config.messageQueueDelay > 0 ? "collecting" : "waiting";
|
|
3273
|
+
turn = {
|
|
3274
|
+
messages: [],
|
|
3266
3275
|
userName,
|
|
3267
|
-
|
|
3268
|
-
collectWaiters: [],
|
|
3269
|
-
state: config.messageQueueDelay > 0 ? "collecting" : "processing"
|
|
3276
|
+
state
|
|
3270
3277
|
};
|
|
3271
|
-
|
|
3272
|
-
if (config.messageQueueDelay > 0) {
|
|
3273
|
-
resetBatchTimeout(ctx, config, newBatch, conversationId);
|
|
3274
|
-
return await awaitCollectingBatch(newBatch, context);
|
|
3275
|
-
}
|
|
3276
|
-
newBatch.messages = [];
|
|
3277
|
-
return 2 /* CONTINUE */;
|
|
3278
|
-
}
|
|
3279
|
-
if (batch.userName !== userName) {
|
|
3280
|
-
logger6.debug(
|
|
3281
|
-
`User mismatch for ${conversationId}, messageId: ${messageId}, waiting for batch completion`
|
|
3282
|
-
);
|
|
3283
|
-
return await waitForBatchCompletion(
|
|
3284
|
-
batch,
|
|
3285
|
-
conversationId,
|
|
3286
|
-
inputMessage,
|
|
3287
|
-
userName,
|
|
3288
|
-
context
|
|
3289
|
-
);
|
|
3290
|
-
}
|
|
3291
|
-
if (batch.state === "collecting") {
|
|
3278
|
+
conversation.turns.push(turn);
|
|
3292
3279
|
logger6.debug(
|
|
3293
|
-
`
|
|
3280
|
+
`Creating new turn for ${conversationId}, messageId: ${messageId}, user: ${userName}, queue: ${conversation.turns.length}`
|
|
3294
3281
|
);
|
|
3295
|
-
batch.messages.push(inputMessage);
|
|
3296
|
-
if (config.messageQueueDelay > 0) {
|
|
3297
|
-
resetBatchTimeout(ctx, config, batch, conversationId);
|
|
3298
|
-
}
|
|
3299
|
-
return await awaitCollectingBatch(batch, context);
|
|
3300
3282
|
}
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
)
|
|
3304
|
-
|
|
3305
|
-
if (status === 1 /* STOP */) {
|
|
3306
|
-
return status;
|
|
3283
|
+
turn.messages.push(inputMessage);
|
|
3284
|
+
const statusPromise = awaitTurnStart(turn, context);
|
|
3285
|
+
if (turn.state === "collecting") {
|
|
3286
|
+
resetTurnTimeout(ctx, config, conversationId, turn);
|
|
3307
3287
|
}
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
);
|
|
3311
|
-
return interruptAndMerge(batch, context);
|
|
3288
|
+
tryStartHeadTurn(conversationId, conversation);
|
|
3289
|
+
return await statusPromise;
|
|
3312
3290
|
}).after("check_room").after("read_chat_message").before("lifecycle-handle_command");
|
|
3313
|
-
const
|
|
3314
|
-
const
|
|
3315
|
-
if (
|
|
3291
|
+
const completeTurn = /* @__PURE__ */ __name(async (conversationId) => {
|
|
3292
|
+
const conversation = queues.get(conversationId);
|
|
3293
|
+
if (!conversation) {
|
|
3294
|
+
return;
|
|
3295
|
+
}
|
|
3296
|
+
const current = conversation.turns.shift();
|
|
3297
|
+
conversation.inFlight = false;
|
|
3298
|
+
if (current?.timeout) {
|
|
3299
|
+
current.timeout();
|
|
3300
|
+
}
|
|
3301
|
+
if (current?.starter) {
|
|
3302
|
+
current.starter.resolve(1 /* STOP */);
|
|
3303
|
+
current.starter = void 0;
|
|
3304
|
+
}
|
|
3305
|
+
if (conversation.turns.length === 0) {
|
|
3306
|
+
queues.delete(conversationId);
|
|
3307
|
+
return;
|
|
3308
|
+
}
|
|
3309
|
+
tryStartHeadTurn(conversationId, conversation);
|
|
3310
|
+
if (current) {
|
|
3316
3311
|
logger6.debug(
|
|
3317
|
-
`Completing
|
|
3318
|
-
);
|
|
3319
|
-
if (batch.timeout) {
|
|
3320
|
-
batch.timeout();
|
|
3321
|
-
}
|
|
3322
|
-
const waiters = batch.resolveWaiters;
|
|
3323
|
-
batch.resolveWaiters = [];
|
|
3324
|
-
waiters.forEach(
|
|
3325
|
-
(resolve) => resolve(2 /* CONTINUE */)
|
|
3312
|
+
`Completing turn for ${conversationId}, remaining: ${conversation.turns.length}`
|
|
3326
3313
|
);
|
|
3327
|
-
} else if (batch) {
|
|
3328
|
-
logger6.debug(`Cleaning up batch for ${conversationId}`);
|
|
3329
|
-
if (batch.timeout) {
|
|
3330
|
-
batch.timeout();
|
|
3331
|
-
}
|
|
3332
|
-
batches.delete(conversationId);
|
|
3333
3314
|
}
|
|
3334
|
-
}, "
|
|
3335
|
-
ctx.on(
|
|
3336
|
-
"chatluna/after-chat",
|
|
3337
|
-
async (conversationId) => await completeBatch(conversationId)
|
|
3338
|
-
);
|
|
3315
|
+
}, "completeTurn");
|
|
3316
|
+
ctx.on("chatluna/after-chat", completeTurn);
|
|
3339
3317
|
ctx.on(
|
|
3340
3318
|
"chatluna/after-chat-error",
|
|
3341
|
-
|
|
3319
|
+
(_, conversationId) => completeTurn(conversationId)
|
|
3342
3320
|
);
|
|
3343
3321
|
ctx.on("chatluna/clear-chat-history", async (conversationId) => {
|
|
3344
|
-
const
|
|
3345
|
-
if (
|
|
3322
|
+
const conversation = queues.get(conversationId);
|
|
3323
|
+
if (conversation) {
|
|
3324
|
+
const stoppedWaiters = conversation.turns.filter(
|
|
3325
|
+
(turn) => !!turn.starter
|
|
3326
|
+
).length;
|
|
3346
3327
|
logger6.debug(
|
|
3347
|
-
`Clearing chat history for ${conversationId}, stopping ${
|
|
3328
|
+
`Clearing chat history for ${conversationId}, stopping ${stoppedWaiters} waiters`
|
|
3348
3329
|
);
|
|
3349
|
-
|
|
3350
|
-
|
|
3330
|
+
for (const turn of conversation.turns) {
|
|
3331
|
+
if (turn.timeout) {
|
|
3332
|
+
turn.timeout();
|
|
3333
|
+
turn.timeout = void 0;
|
|
3334
|
+
}
|
|
3335
|
+
if (turn.starter) {
|
|
3336
|
+
turn.starter.resolve(1 /* STOP */);
|
|
3337
|
+
turn.starter = void 0;
|
|
3338
|
+
}
|
|
3351
3339
|
}
|
|
3352
|
-
|
|
3353
|
-
(resolve) => resolve(1 /* STOP */)
|
|
3354
|
-
);
|
|
3355
|
-
batch.collectWaiters.forEach(
|
|
3356
|
-
(resolve) => resolve(1 /* STOP */)
|
|
3357
|
-
);
|
|
3358
|
-
batches.delete(conversationId);
|
|
3340
|
+
queues.delete(conversationId);
|
|
3359
3341
|
}
|
|
3360
3342
|
});
|
|
3361
3343
|
}
|
|
3362
3344
|
__name(apply25, "apply");
|
|
3363
|
-
function
|
|
3364
|
-
if (
|
|
3365
|
-
|
|
3345
|
+
function awaitTurnStart(turn, context) {
|
|
3346
|
+
if (turn.starter) {
|
|
3347
|
+
turn.starter.resolve(1 /* STOP */);
|
|
3348
|
+
turn.starter = void 0;
|
|
3366
3349
|
}
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
batch.state = "processing";
|
|
3370
|
-
return 2 /* CONTINUE */;
|
|
3371
|
-
}
|
|
3372
|
-
__name(interruptAndMerge, "interruptAndMerge");
|
|
3373
|
-
async function awaitCollectingBatch(batch, context) {
|
|
3374
|
-
resolveCollectWaiters(batch, 1 /* STOP */);
|
|
3375
|
-
return await new Promise((resolve) => {
|
|
3376
|
-
batch.collectWaiters.push((status) => {
|
|
3377
|
-
if (status === 1 /* STOP */) {
|
|
3378
|
-
resolve(1 /* STOP */);
|
|
3379
|
-
return;
|
|
3380
|
-
}
|
|
3381
|
-
context.options.inputMessage = mergeMessages(batch.messages);
|
|
3382
|
-
batch.messages = [];
|
|
3383
|
-
batch.state = "processing";
|
|
3384
|
-
resolve(2 /* CONTINUE */);
|
|
3385
|
-
});
|
|
3350
|
+
return new Promise((resolve) => {
|
|
3351
|
+
turn.starter = { resolve, context };
|
|
3386
3352
|
});
|
|
3387
3353
|
}
|
|
3388
|
-
__name(
|
|
3389
|
-
function
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
waiters.forEach((resolve) => resolve(status));
|
|
3393
|
-
}
|
|
3394
|
-
__name(resolveCollectWaiters, "resolveCollectWaiters");
|
|
3395
|
-
function resetBatchTimeout(ctx, config, batch, conversationId) {
|
|
3396
|
-
if (batch.timeout) {
|
|
3397
|
-
batch.timeout();
|
|
3354
|
+
__name(awaitTurnStart, "awaitTurnStart");
|
|
3355
|
+
function resetTurnTimeout(ctx, config, conversationId, turn) {
|
|
3356
|
+
if (turn.timeout) {
|
|
3357
|
+
turn.timeout();
|
|
3398
3358
|
}
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
`Delay timeout (${config.messageQueueDelay}s) for ${conversationId}, processing batch with ${batch.messages.length} messages`
|
|
3404
|
-
);
|
|
3405
|
-
batch.timeout = void 0;
|
|
3406
|
-
resolveCollectWaiters(batch, 2 /* CONTINUE */);
|
|
3359
|
+
turn.timeout = ctx.setTimeout(() => {
|
|
3360
|
+
const conversation = queues.get(conversationId);
|
|
3361
|
+
if (!conversation || conversation.turns[0] !== turn) {
|
|
3362
|
+
return;
|
|
3407
3363
|
}
|
|
3364
|
+
turn.state = "waiting";
|
|
3365
|
+
turn.timeout = void 0;
|
|
3366
|
+
if (conversation.inFlight) {
|
|
3367
|
+
return;
|
|
3368
|
+
}
|
|
3369
|
+
logger6.debug(
|
|
3370
|
+
// eslint-disable-next-line max-len
|
|
3371
|
+
`Delay timeout (${config.messageQueueDelay}s) for ${conversationId}, starting turn with ${turn.messages.length} messages`
|
|
3372
|
+
);
|
|
3373
|
+
startHeadTurn(conversationId, conversation, turn);
|
|
3408
3374
|
}, config.messageQueueDelay * 1e3);
|
|
3409
3375
|
}
|
|
3410
|
-
__name(
|
|
3411
|
-
|
|
3412
|
-
if (
|
|
3413
|
-
|
|
3414
|
-
} else {
|
|
3415
|
-
batch.messages.push(message);
|
|
3376
|
+
__name(resetTurnTimeout, "resetTurnTimeout");
|
|
3377
|
+
function tryStartHeadTurn(conversationId, conversation) {
|
|
3378
|
+
if (conversation.inFlight) {
|
|
3379
|
+
return;
|
|
3416
3380
|
}
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
}
|
|
3381
|
+
const head = conversation.turns[0];
|
|
3382
|
+
if (!head) {
|
|
3383
|
+
queues.delete(conversationId);
|
|
3384
|
+
return;
|
|
3385
|
+
}
|
|
3386
|
+
if (head.state === "collecting") {
|
|
3387
|
+
return;
|
|
3388
|
+
}
|
|
3389
|
+
startHeadTurn(conversationId, conversation, head);
|
|
3422
3390
|
}
|
|
3423
|
-
__name(
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
batches.delete(conversationId);
|
|
3446
|
-
resolve(2 /* CONTINUE */);
|
|
3447
|
-
}
|
|
3448
|
-
],
|
|
3449
|
-
collectWaiters: [],
|
|
3450
|
-
state: "processing"
|
|
3451
|
-
});
|
|
3452
|
-
});
|
|
3453
|
-
});
|
|
3391
|
+
__name(tryStartHeadTurn, "tryStartHeadTurn");
|
|
3392
|
+
function startHeadTurn(conversationId, conversation, head) {
|
|
3393
|
+
if (conversation.inFlight) {
|
|
3394
|
+
return;
|
|
3395
|
+
}
|
|
3396
|
+
if (conversation.turns[0] !== head) {
|
|
3397
|
+
return;
|
|
3398
|
+
}
|
|
3399
|
+
if (!head.starter) {
|
|
3400
|
+
return;
|
|
3401
|
+
}
|
|
3402
|
+
if (head.timeout) {
|
|
3403
|
+
head.timeout();
|
|
3404
|
+
head.timeout = void 0;
|
|
3405
|
+
}
|
|
3406
|
+
const starter = head.starter;
|
|
3407
|
+
head.starter = void 0;
|
|
3408
|
+
conversation.inFlight = true;
|
|
3409
|
+
head.state = "processing";
|
|
3410
|
+
starter.context.options.inputMessage = mergeMessages(head.messages);
|
|
3411
|
+
head.messages = [];
|
|
3412
|
+
starter.resolve(2 /* CONTINUE */);
|
|
3454
3413
|
}
|
|
3455
|
-
__name(
|
|
3414
|
+
__name(startHeadTurn, "startHeadTurn");
|
|
3456
3415
|
function mergeMessages(messages) {
|
|
3457
3416
|
if (messages.length === 1) return messages[0];
|
|
3458
3417
|
const base = messages[0];
|
|
@@ -3626,8 +3585,86 @@ function apply26(ctx, config, chain) {
|
|
|
3626
3585
|
)
|
|
3627
3586
|
);
|
|
3628
3587
|
});
|
|
3588
|
+
ctx.inject(["chatluna_storage"], (ctx2) => {
|
|
3589
|
+
logger7.debug("chatluna_storage service loaded.");
|
|
3590
|
+
ctx2.effect(
|
|
3591
|
+
() => ctx2.chatluna.messageTransformer.intercept(
|
|
3592
|
+
"file",
|
|
3593
|
+
async (session, element, message) => {
|
|
3594
|
+
const fileName = element.attrs["file"] ?? element.attrs["name"];
|
|
3595
|
+
const src = element.attrs["src"];
|
|
3596
|
+
let buffer;
|
|
3597
|
+
if (src.startsWith("http")) {
|
|
3598
|
+
buffer = await readFile(ctx2, src);
|
|
3599
|
+
} else {
|
|
3600
|
+
buffer = await readPlatformFile(ctx2, session, element);
|
|
3601
|
+
}
|
|
3602
|
+
if (!buffer?.buffer) {
|
|
3603
|
+
logger7.warn(
|
|
3604
|
+
`Failed to read file for element: ${element.toString()}`
|
|
3605
|
+
);
|
|
3606
|
+
return;
|
|
3607
|
+
}
|
|
3608
|
+
const file = await ctx2.chatluna_storage.createTempFile(
|
|
3609
|
+
buffer.buffer,
|
|
3610
|
+
fileName
|
|
3611
|
+
);
|
|
3612
|
+
addMessageContent(message, `File: ${file.name} ${file.url}`);
|
|
3613
|
+
}
|
|
3614
|
+
)
|
|
3615
|
+
);
|
|
3616
|
+
});
|
|
3629
3617
|
}
|
|
3630
3618
|
__name(apply26, "apply");
|
|
3619
|
+
async function readPlatformFile(ctx, session, element) {
|
|
3620
|
+
const fileId = element.attrs["fileId"];
|
|
3621
|
+
let fileUrl;
|
|
3622
|
+
if (session.platform === "onebot") {
|
|
3623
|
+
const bot = session.bot;
|
|
3624
|
+
if (session.isDirect) {
|
|
3625
|
+
fileUrl = await bot.internal.getPrivateFileUrl(
|
|
3626
|
+
session.userId,
|
|
3627
|
+
fileId
|
|
3628
|
+
);
|
|
3629
|
+
} else {
|
|
3630
|
+
fileUrl = await bot.internal.getGroupFileUrl(
|
|
3631
|
+
session.guildId,
|
|
3632
|
+
fileId,
|
|
3633
|
+
element["busId"]
|
|
3634
|
+
);
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
if (!fileUrl) {
|
|
3638
|
+
logger7.warn(`Failed to get file URL for element: ${element.toString()}`);
|
|
3639
|
+
return;
|
|
3640
|
+
}
|
|
3641
|
+
return await readFile(ctx, fileUrl);
|
|
3642
|
+
}
|
|
3643
|
+
__name(readPlatformFile, "readPlatformFile");
|
|
3644
|
+
async function readFile(ctx, url) {
|
|
3645
|
+
try {
|
|
3646
|
+
const response = await ctx.http(url, {
|
|
3647
|
+
responseType: "arraybuffer",
|
|
3648
|
+
method: "get",
|
|
3649
|
+
headers: {
|
|
3650
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"
|
|
3651
|
+
}
|
|
3652
|
+
});
|
|
3653
|
+
const buffer = Buffer.from(response.data);
|
|
3654
|
+
const base64 = buffer.toString("base64");
|
|
3655
|
+
return {
|
|
3656
|
+
base64Source: base64,
|
|
3657
|
+
buffer
|
|
3658
|
+
};
|
|
3659
|
+
} catch (error) {
|
|
3660
|
+
logger7.error(`Failed to read file from ${url}:`, error);
|
|
3661
|
+
return {
|
|
3662
|
+
base64Source: null,
|
|
3663
|
+
buffer: null
|
|
3664
|
+
};
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
__name(readFile, "readFile");
|
|
3631
3668
|
async function readImage(ctx, url) {
|
|
3632
3669
|
if (url.startsWith("data:image") && url.includes("base64")) {
|
|
3633
3670
|
const buffer = Buffer.from(url.split(",")[1], "base64");
|
|
@@ -22,4 +22,4 @@ export type CreateOpenAIAgentParams = {
|
|
|
22
22
|
};
|
|
23
23
|
export declare function createOpenAIAgent({ llm, tools, prompt }: CreateOpenAIAgentParams): RunnableSequence<{
|
|
24
24
|
steps: AgentStep[];
|
|
25
|
-
}, AgentAction |
|
|
25
|
+
}, AgentAction | AgentAction[] | AgentFinish>;
|
|
@@ -12,7 +12,7 @@ export declare class OpenAIFunctionsAgentOutputParser extends AgentActionOutputP
|
|
|
12
12
|
lc_namespace: string[];
|
|
13
13
|
static lc_name(): string;
|
|
14
14
|
parse(text: string): Promise<AgentAction | AgentFinish>;
|
|
15
|
-
parseResult(generations: ChatGeneration[]): Promise<
|
|
15
|
+
parseResult(generations: ChatGeneration[]): Promise<AgentFinish | FunctionsAgentAction>;
|
|
16
16
|
/**
|
|
17
17
|
* Parses the output message into a FunctionsAgentAction or AgentFinish
|
|
18
18
|
* object.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-chatluna",
|
|
3
3
|
"description": "chatluna for koishi",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.8",
|
|
5
5
|
"main": "lib/index.cjs",
|
|
6
6
|
"module": "lib/index.mjs",
|
|
7
7
|
"typings": "lib/index.d.ts",
|
|
@@ -226,8 +226,8 @@
|
|
|
226
226
|
"langchain"
|
|
227
227
|
],
|
|
228
228
|
"dependencies": {
|
|
229
|
-
"@chatluna/shared-prompt-renderer": "^1.0.
|
|
230
|
-
"@langchain/core": "0.3.
|
|
229
|
+
"@chatluna/shared-prompt-renderer": "^1.0.4",
|
|
230
|
+
"@langchain/core": "^0.3.80",
|
|
231
231
|
"@vue/reactivity": "^3.6.0-alpha.2",
|
|
232
232
|
"decimal.js": "^10.6.0",
|
|
233
233
|
"he": "^1.2.0",
|
|
@@ -254,11 +254,12 @@
|
|
|
254
254
|
"@types/js-yaml": "^4.0.9",
|
|
255
255
|
"@types/qrcode": "^1.5.5",
|
|
256
256
|
"@types/useragent": "^2",
|
|
257
|
-
"atsc": "^2.1.0"
|
|
257
|
+
"atsc": "^2.1.0",
|
|
258
|
+
"koishi-plugin-adapter-onebot": "^6.8.0"
|
|
258
259
|
},
|
|
259
260
|
"peerDependencies": {
|
|
260
261
|
"koishi": "^4.18.9",
|
|
261
|
-
"koishi-plugin-chatluna-storage-service": "^
|
|
262
|
+
"koishi-plugin-chatluna-storage-service": "^1.0.1"
|
|
262
263
|
},
|
|
263
264
|
"peerDependenciesMeta": {
|
|
264
265
|
"koishi-plugin-chatluna-storage-service": {
|
|
@@ -266,16 +267,16 @@
|
|
|
266
267
|
}
|
|
267
268
|
},
|
|
268
269
|
"resolutions": {
|
|
269
|
-
"@langchain/core": "0.3.
|
|
270
|
+
"@langchain/core": "^0.3.80",
|
|
270
271
|
"js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.21"
|
|
271
272
|
},
|
|
272
273
|
"overrides": {
|
|
273
|
-
"@langchain/core": "0.3.
|
|
274
|
+
"@langchain/core": "^0.3.80",
|
|
274
275
|
"js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.21"
|
|
275
276
|
},
|
|
276
277
|
"pnpm": {
|
|
277
278
|
"overrides": {
|
|
278
|
-
"@langchain/core": "0.3.
|
|
279
|
+
"@langchain/core": "^0.3.80",
|
|
279
280
|
"js-tiktoken": "npm:@dingyi222666/js-tiktoken@^1.0.21"
|
|
280
281
|
}
|
|
281
282
|
},
|