koishi-plugin-chatluna 1.3.6 → 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 +207 -138
- package/lib/index.mjs +207 -138
- 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,171 +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
|
-
|
|
3281
|
+
state
|
|
3273
3282
|
};
|
|
3274
|
-
|
|
3275
|
-
if (config.messageQueueDelay > 0) {
|
|
3276
|
-
return await new Promise(
|
|
3277
|
-
(resolve) => {
|
|
3278
|
-
newBatch.processorResolve = resolve;
|
|
3279
|
-
newBatch.timeout = ctx.setTimeout(() => {
|
|
3280
|
-
if (batches.get(conversationId) === newBatch) {
|
|
3281
|
-
logger6.debug(
|
|
3282
|
-
// eslint-disable-next-line max-len
|
|
3283
|
-
`Delay timeout (${config.messageQueueDelay}s) for ${conversationId}, processing batch with ${newBatch.messages.length} messages`
|
|
3284
|
-
);
|
|
3285
|
-
context.options.inputMessage = mergeMessages(newBatch.messages);
|
|
3286
|
-
batches.delete(conversationId);
|
|
3287
|
-
resolve(2 /* CONTINUE */);
|
|
3288
|
-
}
|
|
3289
|
-
}, config.messageQueueDelay * 1e3);
|
|
3290
|
-
}
|
|
3291
|
-
);
|
|
3292
|
-
}
|
|
3293
|
-
return 2 /* CONTINUE */;
|
|
3294
|
-
}
|
|
3295
|
-
if (batch.userName !== userName) {
|
|
3283
|
+
conversation.turns.push(turn);
|
|
3296
3284
|
logger6.debug(
|
|
3297
|
-
`
|
|
3298
|
-
);
|
|
3299
|
-
return await waitForBatchCompletion(
|
|
3300
|
-
batch,
|
|
3301
|
-
conversationId,
|
|
3302
|
-
inputMessage,
|
|
3303
|
-
userName,
|
|
3304
|
-
context
|
|
3285
|
+
`Creating new turn for ${conversationId}, messageId: ${messageId}, user: ${userName}, queue: ${conversation.turns.length}`
|
|
3305
3286
|
);
|
|
3306
3287
|
}
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
);
|
|
3311
|
-
batch.messages.push(inputMessage);
|
|
3312
|
-
if (config.messageQueueDelay > 0 && batch.timeout && batch.processorResolve) {
|
|
3313
|
-
batch.timeout();
|
|
3314
|
-
batch.timeout = ctx.setTimeout(() => {
|
|
3315
|
-
if (batches.get(conversationId) === batch && batch.processorResolve) {
|
|
3316
|
-
logger6.debug(
|
|
3317
|
-
`Delay timeout (${config.messageQueueDelay}s) for ${conversationId}, processing batch with ${batch.messages.length} messages`
|
|
3318
|
-
);
|
|
3319
|
-
context.options.inputMessage = mergeMessages(
|
|
3320
|
-
batch.messages
|
|
3321
|
-
);
|
|
3322
|
-
batches.delete(conversationId);
|
|
3323
|
-
batch.processorResolve(
|
|
3324
|
-
2 /* CONTINUE */
|
|
3325
|
-
);
|
|
3326
|
-
}
|
|
3327
|
-
}, config.messageQueueDelay * 1e3);
|
|
3328
|
-
}
|
|
3329
|
-
return 1 /* STOP */;
|
|
3288
|
+
turn.messages.push(inputMessage);
|
|
3289
|
+
const statusPromise = awaitTurnStart(turn, context);
|
|
3290
|
+
if (turn.state === "collecting") {
|
|
3291
|
+
resetTurnTimeout(ctx, config, conversationId, turn);
|
|
3330
3292
|
}
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
);
|
|
3334
|
-
return await interruptAndMerge(batch, inputMessage, context);
|
|
3293
|
+
tryStartHeadTurn(conversationId, conversation);
|
|
3294
|
+
return await statusPromise;
|
|
3335
3295
|
}).after("check_room").after("read_chat_message").before("lifecycle-handle_command");
|
|
3336
|
-
const
|
|
3337
|
-
const
|
|
3338
|
-
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) {
|
|
3339
3316
|
logger6.debug(
|
|
3340
|
-
`Completing
|
|
3317
|
+
`Completing turn for ${conversationId}, remaining: ${conversation.turns.length}`
|
|
3341
3318
|
);
|
|
3342
|
-
if (batch.timeout) {
|
|
3343
|
-
batch.timeout();
|
|
3344
|
-
}
|
|
3345
|
-
batch.resolveWaiters.forEach((resolve) => resolve());
|
|
3346
|
-
batches.delete(conversationId);
|
|
3347
|
-
} else if (batch) {
|
|
3348
|
-
logger6.debug(`Cleaning up batch for ${conversationId}`);
|
|
3349
|
-
if (batch.timeout) {
|
|
3350
|
-
batch.timeout();
|
|
3351
|
-
}
|
|
3352
|
-
if (batch.processorResolve) {
|
|
3353
|
-
batch.processorResolve(1 /* STOP */);
|
|
3354
|
-
}
|
|
3355
|
-
batches.delete(conversationId);
|
|
3356
3319
|
}
|
|
3357
|
-
}, "
|
|
3358
|
-
ctx.on(
|
|
3359
|
-
"chatluna/after-chat",
|
|
3360
|
-
async (conversationId) => await completeBatch(conversationId)
|
|
3361
|
-
);
|
|
3320
|
+
}, "completeTurn");
|
|
3321
|
+
ctx.on("chatluna/after-chat", completeTurn);
|
|
3362
3322
|
ctx.on(
|
|
3363
3323
|
"chatluna/after-chat-error",
|
|
3364
|
-
|
|
3324
|
+
(_, conversationId) => completeTurn(conversationId)
|
|
3365
3325
|
);
|
|
3366
3326
|
ctx.on("chatluna/clear-chat-history", async (conversationId) => {
|
|
3367
|
-
const
|
|
3368
|
-
if (
|
|
3327
|
+
const conversation = queues.get(conversationId);
|
|
3328
|
+
if (conversation) {
|
|
3329
|
+
const stoppedWaiters = conversation.turns.filter(
|
|
3330
|
+
(turn) => !!turn.starter
|
|
3331
|
+
).length;
|
|
3369
3332
|
logger6.debug(
|
|
3370
|
-
`Clearing chat history for ${conversationId}, stopping ${
|
|
3371
|
-
);
|
|
3372
|
-
if (batch.timeout) {
|
|
3373
|
-
batch.timeout();
|
|
3374
|
-
}
|
|
3375
|
-
batch.resolveWaiters.forEach(
|
|
3376
|
-
(resolve) => resolve(1 /* STOP */)
|
|
3333
|
+
`Clearing chat history for ${conversationId}, stopping ${stoppedWaiters} waiters`
|
|
3377
3334
|
);
|
|
3378
|
-
|
|
3379
|
-
|
|
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
|
+
}
|
|
3380
3344
|
}
|
|
3381
|
-
|
|
3345
|
+
queues.delete(conversationId);
|
|
3382
3346
|
}
|
|
3383
3347
|
});
|
|
3384
3348
|
}
|
|
3385
3349
|
__name(apply25, "apply");
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
batch.processorResolve = void 0;
|
|
3391
|
-
batch.messages.push(message);
|
|
3392
|
-
if (batch.timeout) {
|
|
3393
|
-
batch.timeout();
|
|
3394
|
-
batch.timeout = void 0;
|
|
3395
|
-
}
|
|
3396
|
-
oldWaiters.forEach((resolve) => resolve(1 /* STOP */));
|
|
3397
|
-
if (oldProcessor) {
|
|
3398
|
-
oldProcessor(1 /* STOP */);
|
|
3350
|
+
function awaitTurnStart(turn, context) {
|
|
3351
|
+
if (turn.starter) {
|
|
3352
|
+
turn.starter.resolve(1 /* STOP */);
|
|
3353
|
+
turn.starter = void 0;
|
|
3399
3354
|
}
|
|
3400
3355
|
return new Promise((resolve) => {
|
|
3401
|
-
|
|
3402
|
-
context.options.inputMessage = mergeMessages(batch.messages);
|
|
3403
|
-
resolve(2 /* CONTINUE */);
|
|
3404
|
-
});
|
|
3356
|
+
turn.starter = { resolve, context };
|
|
3405
3357
|
});
|
|
3406
3358
|
}
|
|
3407
|
-
__name(
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
})
|
|
3425
|
-
|
|
3426
|
-
|
|
3359
|
+
__name(awaitTurnStart, "awaitTurnStart");
|
|
3360
|
+
function resetTurnTimeout(ctx, config, conversationId, turn) {
|
|
3361
|
+
if (turn.timeout) {
|
|
3362
|
+
turn.timeout();
|
|
3363
|
+
}
|
|
3364
|
+
turn.timeout = ctx.setTimeout(() => {
|
|
3365
|
+
const conversation = queues.get(conversationId);
|
|
3366
|
+
if (!conversation || conversation.turns[0] !== turn) {
|
|
3367
|
+
return;
|
|
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);
|
|
3379
|
+
}, config.messageQueueDelay * 1e3);
|
|
3427
3380
|
}
|
|
3428
|
-
__name(
|
|
3381
|
+
__name(resetTurnTimeout, "resetTurnTimeout");
|
|
3382
|
+
function tryStartHeadTurn(conversationId, conversation) {
|
|
3383
|
+
if (conversation.inFlight) {
|
|
3384
|
+
return;
|
|
3385
|
+
}
|
|
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);
|
|
3395
|
+
}
|
|
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 */);
|
|
3418
|
+
}
|
|
3419
|
+
__name(startHeadTurn, "startHeadTurn");
|
|
3429
3420
|
function mergeMessages(messages) {
|
|
3430
3421
|
if (messages.length === 1) return messages[0];
|
|
3431
3422
|
const base = messages[0];
|
|
@@ -3595,8 +3586,86 @@ function apply26(ctx, config, chain) {
|
|
|
3595
3586
|
)
|
|
3596
3587
|
);
|
|
3597
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
|
+
});
|
|
3598
3618
|
}
|
|
3599
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");
|
|
3600
3669
|
async function readImage(ctx, url) {
|
|
3601
3670
|
if (url.startsWith("data:image") && url.includes("base64")) {
|
|
3602
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,171 +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
|
-
|
|
3276
|
+
state
|
|
3268
3277
|
};
|
|
3269
|
-
|
|
3270
|
-
if (config.messageQueueDelay > 0) {
|
|
3271
|
-
return await new Promise(
|
|
3272
|
-
(resolve) => {
|
|
3273
|
-
newBatch.processorResolve = resolve;
|
|
3274
|
-
newBatch.timeout = ctx.setTimeout(() => {
|
|
3275
|
-
if (batches.get(conversationId) === newBatch) {
|
|
3276
|
-
logger6.debug(
|
|
3277
|
-
// eslint-disable-next-line max-len
|
|
3278
|
-
`Delay timeout (${config.messageQueueDelay}s) for ${conversationId}, processing batch with ${newBatch.messages.length} messages`
|
|
3279
|
-
);
|
|
3280
|
-
context.options.inputMessage = mergeMessages(newBatch.messages);
|
|
3281
|
-
batches.delete(conversationId);
|
|
3282
|
-
resolve(2 /* CONTINUE */);
|
|
3283
|
-
}
|
|
3284
|
-
}, config.messageQueueDelay * 1e3);
|
|
3285
|
-
}
|
|
3286
|
-
);
|
|
3287
|
-
}
|
|
3288
|
-
return 2 /* CONTINUE */;
|
|
3289
|
-
}
|
|
3290
|
-
if (batch.userName !== userName) {
|
|
3278
|
+
conversation.turns.push(turn);
|
|
3291
3279
|
logger6.debug(
|
|
3292
|
-
`
|
|
3293
|
-
);
|
|
3294
|
-
return await waitForBatchCompletion(
|
|
3295
|
-
batch,
|
|
3296
|
-
conversationId,
|
|
3297
|
-
inputMessage,
|
|
3298
|
-
userName,
|
|
3299
|
-
context
|
|
3280
|
+
`Creating new turn for ${conversationId}, messageId: ${messageId}, user: ${userName}, queue: ${conversation.turns.length}`
|
|
3300
3281
|
);
|
|
3301
3282
|
}
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
);
|
|
3306
|
-
batch.messages.push(inputMessage);
|
|
3307
|
-
if (config.messageQueueDelay > 0 && batch.timeout && batch.processorResolve) {
|
|
3308
|
-
batch.timeout();
|
|
3309
|
-
batch.timeout = ctx.setTimeout(() => {
|
|
3310
|
-
if (batches.get(conversationId) === batch && batch.processorResolve) {
|
|
3311
|
-
logger6.debug(
|
|
3312
|
-
`Delay timeout (${config.messageQueueDelay}s) for ${conversationId}, processing batch with ${batch.messages.length} messages`
|
|
3313
|
-
);
|
|
3314
|
-
context.options.inputMessage = mergeMessages(
|
|
3315
|
-
batch.messages
|
|
3316
|
-
);
|
|
3317
|
-
batches.delete(conversationId);
|
|
3318
|
-
batch.processorResolve(
|
|
3319
|
-
2 /* CONTINUE */
|
|
3320
|
-
);
|
|
3321
|
-
}
|
|
3322
|
-
}, config.messageQueueDelay * 1e3);
|
|
3323
|
-
}
|
|
3324
|
-
return 1 /* STOP */;
|
|
3283
|
+
turn.messages.push(inputMessage);
|
|
3284
|
+
const statusPromise = awaitTurnStart(turn, context);
|
|
3285
|
+
if (turn.state === "collecting") {
|
|
3286
|
+
resetTurnTimeout(ctx, config, conversationId, turn);
|
|
3325
3287
|
}
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
);
|
|
3329
|
-
return await interruptAndMerge(batch, inputMessage, context);
|
|
3288
|
+
tryStartHeadTurn(conversationId, conversation);
|
|
3289
|
+
return await statusPromise;
|
|
3330
3290
|
}).after("check_room").after("read_chat_message").before("lifecycle-handle_command");
|
|
3331
|
-
const
|
|
3332
|
-
const
|
|
3333
|
-
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) {
|
|
3334
3311
|
logger6.debug(
|
|
3335
|
-
`Completing
|
|
3312
|
+
`Completing turn for ${conversationId}, remaining: ${conversation.turns.length}`
|
|
3336
3313
|
);
|
|
3337
|
-
if (batch.timeout) {
|
|
3338
|
-
batch.timeout();
|
|
3339
|
-
}
|
|
3340
|
-
batch.resolveWaiters.forEach((resolve) => resolve());
|
|
3341
|
-
batches.delete(conversationId);
|
|
3342
|
-
} else if (batch) {
|
|
3343
|
-
logger6.debug(`Cleaning up batch for ${conversationId}`);
|
|
3344
|
-
if (batch.timeout) {
|
|
3345
|
-
batch.timeout();
|
|
3346
|
-
}
|
|
3347
|
-
if (batch.processorResolve) {
|
|
3348
|
-
batch.processorResolve(1 /* STOP */);
|
|
3349
|
-
}
|
|
3350
|
-
batches.delete(conversationId);
|
|
3351
3314
|
}
|
|
3352
|
-
}, "
|
|
3353
|
-
ctx.on(
|
|
3354
|
-
"chatluna/after-chat",
|
|
3355
|
-
async (conversationId) => await completeBatch(conversationId)
|
|
3356
|
-
);
|
|
3315
|
+
}, "completeTurn");
|
|
3316
|
+
ctx.on("chatluna/after-chat", completeTurn);
|
|
3357
3317
|
ctx.on(
|
|
3358
3318
|
"chatluna/after-chat-error",
|
|
3359
|
-
|
|
3319
|
+
(_, conversationId) => completeTurn(conversationId)
|
|
3360
3320
|
);
|
|
3361
3321
|
ctx.on("chatluna/clear-chat-history", async (conversationId) => {
|
|
3362
|
-
const
|
|
3363
|
-
if (
|
|
3322
|
+
const conversation = queues.get(conversationId);
|
|
3323
|
+
if (conversation) {
|
|
3324
|
+
const stoppedWaiters = conversation.turns.filter(
|
|
3325
|
+
(turn) => !!turn.starter
|
|
3326
|
+
).length;
|
|
3364
3327
|
logger6.debug(
|
|
3365
|
-
`Clearing chat history for ${conversationId}, stopping ${
|
|
3366
|
-
);
|
|
3367
|
-
if (batch.timeout) {
|
|
3368
|
-
batch.timeout();
|
|
3369
|
-
}
|
|
3370
|
-
batch.resolveWaiters.forEach(
|
|
3371
|
-
(resolve) => resolve(1 /* STOP */)
|
|
3328
|
+
`Clearing chat history for ${conversationId}, stopping ${stoppedWaiters} waiters`
|
|
3372
3329
|
);
|
|
3373
|
-
|
|
3374
|
-
|
|
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
|
+
}
|
|
3375
3339
|
}
|
|
3376
|
-
|
|
3340
|
+
queues.delete(conversationId);
|
|
3377
3341
|
}
|
|
3378
3342
|
});
|
|
3379
3343
|
}
|
|
3380
3344
|
__name(apply25, "apply");
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
batch.processorResolve = void 0;
|
|
3386
|
-
batch.messages.push(message);
|
|
3387
|
-
if (batch.timeout) {
|
|
3388
|
-
batch.timeout();
|
|
3389
|
-
batch.timeout = void 0;
|
|
3390
|
-
}
|
|
3391
|
-
oldWaiters.forEach((resolve) => resolve(1 /* STOP */));
|
|
3392
|
-
if (oldProcessor) {
|
|
3393
|
-
oldProcessor(1 /* STOP */);
|
|
3345
|
+
function awaitTurnStart(turn, context) {
|
|
3346
|
+
if (turn.starter) {
|
|
3347
|
+
turn.starter.resolve(1 /* STOP */);
|
|
3348
|
+
turn.starter = void 0;
|
|
3394
3349
|
}
|
|
3395
3350
|
return new Promise((resolve) => {
|
|
3396
|
-
|
|
3397
|
-
context.options.inputMessage = mergeMessages(batch.messages);
|
|
3398
|
-
resolve(2 /* CONTINUE */);
|
|
3399
|
-
});
|
|
3351
|
+
turn.starter = { resolve, context };
|
|
3400
3352
|
});
|
|
3401
3353
|
}
|
|
3402
|
-
__name(
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
})
|
|
3420
|
-
|
|
3421
|
-
|
|
3354
|
+
__name(awaitTurnStart, "awaitTurnStart");
|
|
3355
|
+
function resetTurnTimeout(ctx, config, conversationId, turn) {
|
|
3356
|
+
if (turn.timeout) {
|
|
3357
|
+
turn.timeout();
|
|
3358
|
+
}
|
|
3359
|
+
turn.timeout = ctx.setTimeout(() => {
|
|
3360
|
+
const conversation = queues.get(conversationId);
|
|
3361
|
+
if (!conversation || conversation.turns[0] !== turn) {
|
|
3362
|
+
return;
|
|
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);
|
|
3374
|
+
}, config.messageQueueDelay * 1e3);
|
|
3422
3375
|
}
|
|
3423
|
-
__name(
|
|
3376
|
+
__name(resetTurnTimeout, "resetTurnTimeout");
|
|
3377
|
+
function tryStartHeadTurn(conversationId, conversation) {
|
|
3378
|
+
if (conversation.inFlight) {
|
|
3379
|
+
return;
|
|
3380
|
+
}
|
|
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);
|
|
3390
|
+
}
|
|
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 */);
|
|
3413
|
+
}
|
|
3414
|
+
__name(startHeadTurn, "startHeadTurn");
|
|
3424
3415
|
function mergeMessages(messages) {
|
|
3425
3416
|
if (messages.length === 1) return messages[0];
|
|
3426
3417
|
const base = messages[0];
|
|
@@ -3594,8 +3585,86 @@ function apply26(ctx, config, chain) {
|
|
|
3594
3585
|
)
|
|
3595
3586
|
);
|
|
3596
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
|
+
});
|
|
3597
3617
|
}
|
|
3598
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");
|
|
3599
3668
|
async function readImage(ctx, url) {
|
|
3600
3669
|
if (url.startsWith("data:image") && url.includes("base64")) {
|
|
3601
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
|
},
|