koishi-plugin-chatluna 1.3.3 → 1.3.5

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.
@@ -46,7 +46,7 @@ export declare class ChainMiddleware {
46
46
  constructor(name: string, execute: ChainMiddlewareFunction, graph: ChatChainDependencyGraph);
47
47
  before<T extends keyof ChainMiddlewareName>(name: T): this;
48
48
  after<T extends keyof ChainMiddlewareName>(name: T): this;
49
- run(session: Session, options: ChainMiddlewareContext): Promise<string | ChainMiddlewareRunStatus | h[] | h[][]>;
49
+ run(session: Session, options: ChainMiddlewareContext): Promise<string | h[] | ChainMiddlewareRunStatus | h[][]>;
50
50
  }
51
51
  export interface ChainMiddlewareContext {
52
52
  config: Config;
package/lib/index.cjs CHANGED
@@ -1046,9 +1046,13 @@ var ChatLunaChatChain = class _ChatLunaChatChain extends import_base.ChatLunaLLM
1046
1046
  requests["variables"] = Object.assign(variables ?? {}, {
1047
1047
  prompt: (0, import_string.getMessageContent)(message.content)
1048
1048
  });
1049
+ requests["variables"]["built"] = {
1050
+ conversationId
1051
+ };
1049
1052
  requests["variables_hide"] = requests["variables"];
1050
1053
  requests["configurable"] = {
1051
- session
1054
+ session,
1055
+ conversationId
1052
1056
  };
1053
1057
  requests["id"] = conversationId;
1054
1058
  const response = await (0, import_base.callChatLunaChain)(
@@ -1185,12 +1189,16 @@ var ChatLunaPluginChain = class _ChatLunaPluginChain extends import_base2.ChatLu
1185
1189
  requests["variables"] = Object.assign(variables ?? {}, {
1186
1190
  prompt: (0, import_string2.getMessageContent)(message.content)
1187
1191
  });
1192
+ requests["variables"]["built"] = {
1193
+ conversationId
1194
+ };
1188
1195
  requests["after_user_message"] = new import_messages2.HumanMessage(
1189
1196
  AGENT_AFTER_USER_PROMPT
1190
1197
  );
1191
1198
  requests["variables_hide"] = requests["variables"];
1192
1199
  requests["configurable"] = {
1193
- session
1200
+ session,
1201
+ conversationId
1194
1202
  };
1195
1203
  this._toolsRef.update(session, messages.concat(message));
1196
1204
  const preset = this.preset.value;
@@ -5184,7 +5192,7 @@ function apply48(ctx, config, chain) {
5184
5192
  if (command2 !== "clear_room")
5185
5193
  return 0 /* SKIPPED */;
5186
5194
  let targetRoom = context.options.room;
5187
- if (targetRoom == null && context.options.room_resolve != null) {
5195
+ if (context.options.room_resolve != null) {
5188
5196
  const rooms = await getAllJoinedConversationRoom(
5189
5197
  ctx,
5190
5198
  session,
@@ -5816,6 +5824,7 @@ var import_crypto7 = require("crypto");
5816
5824
  var logger11;
5817
5825
  function apply56(ctx, config, chain) {
5818
5826
  logger11 = (0, import_logger7.createLogger)(ctx);
5827
+ const selectRoomForSession = /* @__PURE__ */ __name(async (session, joinedRooms) => pickContextualRoom(ctx, session, config, joinedRooms), "selectRoomForSession");
5819
5828
  chain.middleware("resolve_room", async (session, context) => {
5820
5829
  let joinRoom = await queryJoinedConversationRoom(
5821
5830
  ctx,
@@ -5858,32 +5867,16 @@ function apply56(ctx, config, chain) {
5858
5867
  session
5859
5868
  );
5860
5869
  if (joinedRooms.length > 0) {
5861
- joinRoom = // 优先加入自己创建的房间
5862
- joinedRooms.find(
5863
- (room) => room.visibility === "private" && room.roomMasterId === session.userId
5864
- ) ?? // 优先加入自己创建的房间
5865
- joinedRooms.find(
5866
- (room) => room.visibility === "template_clone" && room.roomMasterId === session.userId
5870
+ joinRoom = await selectRoomForSession(session, joinedRooms);
5871
+ }
5872
+ if (joinRoom != null) {
5873
+ await switchConversationRoom(ctx, session, joinRoom.roomId);
5874
+ logger11.success(
5875
+ session.text("chatluna.room.auto_switch", [
5876
+ session.userId,
5877
+ joinRoom.roomName
5878
+ ])
5867
5879
  );
5868
- if (config.autoCreateRoomFromUser !== true && joinRoom == null) {
5869
- joinRoom = // 优先加入模版克隆房间
5870
- joinedRooms.find(
5871
- (room) => room.visibility === "template_clone"
5872
- ) ?? joinedRooms[Math.floor(Math.random() * joinedRooms.length)];
5873
- }
5874
- if (joinRoom != null) {
5875
- await switchConversationRoom(
5876
- ctx,
5877
- session,
5878
- joinRoom.roomId
5879
- );
5880
- logger11.success(
5881
- session.text("chatluna.room.auto_switch", [
5882
- session.userId,
5883
- joinRoom.roomName
5884
- ])
5885
- );
5886
- }
5887
5880
  }
5888
5881
  }
5889
5882
  if (joinRoom == null && config.autoCreateRoomFromUser !== true && !session.isDirect && (context.command?.length ?? 0) < 1) {
@@ -5979,6 +5972,34 @@ function apply56(ctx, config, chain) {
5979
5972
  }).after("lifecycle-prepare");
5980
5973
  }
5981
5974
  __name(apply56, "apply");
5975
+ async function pickContextualRoom(ctx, session, config, joinedRooms) {
5976
+ if (joinedRooms.length === 0) {
5977
+ return void 0;
5978
+ }
5979
+ if (!session.isDirect && config.autoCreateRoomFromUser !== true) {
5980
+ const groupRooms = await ctx.database.get("chathub_room_group_member", {
5981
+ groupId: session.guildId,
5982
+ roomId: { $in: joinedRooms.map((room) => room.roomId) }
5983
+ });
5984
+ if (groupRooms.length > 0) {
5985
+ const scopedRoomIds = new Set(groupRooms.map((room) => room.roomId));
5986
+ const findScopedRoom = /* @__PURE__ */ __name((matcher) => joinedRooms.find((room) => {
5987
+ if (!scopedRoomIds.has(room.roomId)) {
5988
+ return false;
5989
+ }
5990
+ return matcher ? matcher(room) : true;
5991
+ }), "findScopedRoom");
5992
+ return findScopedRoom(
5993
+ (room) => room.visibility === "template_clone"
5994
+ ) ?? findScopedRoom();
5995
+ }
5996
+ return void 0;
5997
+ }
5998
+ return joinedRooms.find(
5999
+ (room) => room.visibility === "private" && room.roomMasterId === session.userId
6000
+ ) ?? joinedRooms.find((room) => room.visibility === "private") ?? joinedRooms.find((room) => room.visibility !== "template_clone") ?? joinedRooms[0];
6001
+ }
6002
+ __name(pickContextualRoom, "pickContextualRoom");
5982
6003
 
5983
6004
  // src/middlewares/room/room_info.ts
5984
6005
  function apply57(ctx, config, chain) {
@@ -7329,7 +7350,7 @@ var inject2 = {
7329
7350
  };
7330
7351
  var logger7;
7331
7352
  var usage = `
7332
- ## chatluna v1.3 beta
7353
+ ## chatluna v1.3
7333
7354
 
7334
7355
  ChatLuna 插件交流 QQ 群:282381753 (有问题或出现 Bug 先加群问)
7335
7356
 
package/lib/index.d.ts CHANGED
@@ -24,5 +24,5 @@ export declare const inject2: {
24
24
  };
25
25
  };
26
26
  export declare let logger: Logger;
27
- export declare const usage = "\n## chatluna v1.3 beta\n\nChatLuna \u63D2\u4EF6\u4EA4\u6D41 QQ \u7FA4\uFF1A282381753 \uFF08\u6709\u95EE\u9898\u6216\u51FA\u73B0 Bug \u5148\u52A0\u7FA4\u95EE\uFF09\n\n\u7FA4\u91CC\u76EE\u524D\u6CA1\u6709\u642D\u8F7D\u8BE5\u63D2\u4EF6\u7684 bot\uFF0C\u52A0\u7FA4\u7684\u8BDD\u6700\u597D\u662F\u6765\u8BE2\u95EE\u95EE\u9898\u6216\u8005\u63D0\u51FA\u610F\u89C1\u7684\u3002\n\n\u8BBF\u95EE [https://chatluna.chat](https://chatluna.chat) \u6765\u4E86\u89E3\u5982\u4F55\u4F7F\u7528 Chatluna\u3002\n\u4E5F\u53EF\u4EE5\u8BBF\u95EE [https://preset.chatluna.chat](https://preset.chatluna.chat) \u8FDB\u5165\u5728\u7EBF\u9884\u8BBE\u7F16\u8F91\u5668\u3002\u66F4\u6709\u9884\u8BBE\u5E7F\u573A\u6765\u6D4F\u89C8\u548C\u4E0B\u8F7D\u4F60\u5FC3\u4EEA\u7684\u9884\u8BBE\u3002\n";
27
+ export declare const usage = "\n## chatluna v1.3\n\nChatLuna \u63D2\u4EF6\u4EA4\u6D41 QQ \u7FA4\uFF1A282381753 \uFF08\u6709\u95EE\u9898\u6216\u51FA\u73B0 Bug \u5148\u52A0\u7FA4\u95EE\uFF09\n\n\u7FA4\u91CC\u76EE\u524D\u6CA1\u6709\u642D\u8F7D\u8BE5\u63D2\u4EF6\u7684 bot\uFF0C\u52A0\u7FA4\u7684\u8BDD\u6700\u597D\u662F\u6765\u8BE2\u95EE\u95EE\u9898\u6216\u8005\u63D0\u51FA\u610F\u89C1\u7684\u3002\n\n\u8BBF\u95EE [https://chatluna.chat](https://chatluna.chat) \u6765\u4E86\u89E3\u5982\u4F55\u4F7F\u7528 Chatluna\u3002\n\u4E5F\u53EF\u4EE5\u8BBF\u95EE [https://preset.chatluna.chat](https://preset.chatluna.chat) \u8FDB\u5165\u5728\u7EBF\u9884\u8BBE\u7F16\u8F91\u5668\u3002\u66F4\u6709\u9884\u8BBE\u5E7F\u573A\u6765\u6D4F\u89C8\u548C\u4E0B\u8F7D\u4F60\u5FC3\u4EEA\u7684\u9884\u8BBE\u3002\n";
28
28
  export declare function apply(ctx: Context, config: Config): void;
package/lib/index.mjs CHANGED
@@ -1021,9 +1021,13 @@ var ChatLunaChatChain = class _ChatLunaChatChain extends ChatLunaLLMChainWrapper
1021
1021
  requests["variables"] = Object.assign(variables ?? {}, {
1022
1022
  prompt: getMessageContent(message.content)
1023
1023
  });
1024
+ requests["variables"]["built"] = {
1025
+ conversationId
1026
+ };
1024
1027
  requests["variables_hide"] = requests["variables"];
1025
1028
  requests["configurable"] = {
1026
- session
1029
+ session,
1030
+ conversationId
1027
1031
  };
1028
1032
  requests["id"] = conversationId;
1029
1033
  const response = await callChatLunaChain(
@@ -1168,12 +1172,16 @@ var ChatLunaPluginChain = class _ChatLunaPluginChain extends ChatLunaLLMChainWra
1168
1172
  requests["variables"] = Object.assign(variables ?? {}, {
1169
1173
  prompt: getMessageContent2(message.content)
1170
1174
  });
1175
+ requests["variables"]["built"] = {
1176
+ conversationId
1177
+ };
1171
1178
  requests["after_user_message"] = new HumanMessage(
1172
1179
  AGENT_AFTER_USER_PROMPT
1173
1180
  );
1174
1181
  requests["variables_hide"] = requests["variables"];
1175
1182
  requests["configurable"] = {
1176
- session
1183
+ session,
1184
+ conversationId
1177
1185
  };
1178
1186
  this._toolsRef.update(session, messages.concat(message));
1179
1187
  const preset = this.preset.value;
@@ -5194,7 +5202,7 @@ function apply48(ctx, config, chain) {
5194
5202
  if (command2 !== "clear_room")
5195
5203
  return 0 /* SKIPPED */;
5196
5204
  let targetRoom = context.options.room;
5197
- if (targetRoom == null && context.options.room_resolve != null) {
5205
+ if (context.options.room_resolve != null) {
5198
5206
  const rooms = await getAllJoinedConversationRoom(
5199
5207
  ctx,
5200
5208
  session,
@@ -5826,6 +5834,7 @@ import { randomUUID as randomUUID4 } from "crypto";
5826
5834
  var logger11;
5827
5835
  function apply56(ctx, config, chain) {
5828
5836
  logger11 = createLogger7(ctx);
5837
+ const selectRoomForSession = /* @__PURE__ */ __name(async (session, joinedRooms) => pickContextualRoom(ctx, session, config, joinedRooms), "selectRoomForSession");
5829
5838
  chain.middleware("resolve_room", async (session, context) => {
5830
5839
  let joinRoom = await queryJoinedConversationRoom(
5831
5840
  ctx,
@@ -5868,32 +5877,16 @@ function apply56(ctx, config, chain) {
5868
5877
  session
5869
5878
  );
5870
5879
  if (joinedRooms.length > 0) {
5871
- joinRoom = // 优先加入自己创建的房间
5872
- joinedRooms.find(
5873
- (room) => room.visibility === "private" && room.roomMasterId === session.userId
5874
- ) ?? // 优先加入自己创建的房间
5875
- joinedRooms.find(
5876
- (room) => room.visibility === "template_clone" && room.roomMasterId === session.userId
5880
+ joinRoom = await selectRoomForSession(session, joinedRooms);
5881
+ }
5882
+ if (joinRoom != null) {
5883
+ await switchConversationRoom(ctx, session, joinRoom.roomId);
5884
+ logger11.success(
5885
+ session.text("chatluna.room.auto_switch", [
5886
+ session.userId,
5887
+ joinRoom.roomName
5888
+ ])
5877
5889
  );
5878
- if (config.autoCreateRoomFromUser !== true && joinRoom == null) {
5879
- joinRoom = // 优先加入模版克隆房间
5880
- joinedRooms.find(
5881
- (room) => room.visibility === "template_clone"
5882
- ) ?? joinedRooms[Math.floor(Math.random() * joinedRooms.length)];
5883
- }
5884
- if (joinRoom != null) {
5885
- await switchConversationRoom(
5886
- ctx,
5887
- session,
5888
- joinRoom.roomId
5889
- );
5890
- logger11.success(
5891
- session.text("chatluna.room.auto_switch", [
5892
- session.userId,
5893
- joinRoom.roomName
5894
- ])
5895
- );
5896
- }
5897
5890
  }
5898
5891
  }
5899
5892
  if (joinRoom == null && config.autoCreateRoomFromUser !== true && !session.isDirect && (context.command?.length ?? 0) < 1) {
@@ -5989,6 +5982,34 @@ function apply56(ctx, config, chain) {
5989
5982
  }).after("lifecycle-prepare");
5990
5983
  }
5991
5984
  __name(apply56, "apply");
5985
+ async function pickContextualRoom(ctx, session, config, joinedRooms) {
5986
+ if (joinedRooms.length === 0) {
5987
+ return void 0;
5988
+ }
5989
+ if (!session.isDirect && config.autoCreateRoomFromUser !== true) {
5990
+ const groupRooms = await ctx.database.get("chathub_room_group_member", {
5991
+ groupId: session.guildId,
5992
+ roomId: { $in: joinedRooms.map((room) => room.roomId) }
5993
+ });
5994
+ if (groupRooms.length > 0) {
5995
+ const scopedRoomIds = new Set(groupRooms.map((room) => room.roomId));
5996
+ const findScopedRoom = /* @__PURE__ */ __name((matcher) => joinedRooms.find((room) => {
5997
+ if (!scopedRoomIds.has(room.roomId)) {
5998
+ return false;
5999
+ }
6000
+ return matcher ? matcher(room) : true;
6001
+ }), "findScopedRoom");
6002
+ return findScopedRoom(
6003
+ (room) => room.visibility === "template_clone"
6004
+ ) ?? findScopedRoom();
6005
+ }
6006
+ return void 0;
6007
+ }
6008
+ return joinedRooms.find(
6009
+ (room) => room.visibility === "private" && room.roomMasterId === session.userId
6010
+ ) ?? joinedRooms.find((room) => room.visibility === "private") ?? joinedRooms.find((room) => room.visibility !== "template_clone") ?? joinedRooms[0];
6011
+ }
6012
+ __name(pickContextualRoom, "pickContextualRoom");
5992
6013
 
5993
6014
  // src/middlewares/room/room_info.ts
5994
6015
  function apply57(ctx, config, chain) {
@@ -7342,7 +7363,7 @@ var inject2 = {
7342
7363
  };
7343
7364
  var logger7;
7344
7365
  var usage = `
7345
- ## chatluna v1.3 beta
7366
+ ## chatluna v1.3
7346
7367
 
7347
7368
  ChatLuna 插件交流 QQ 群:282381753 (有问题或出现 Bug 先加群问)
7348
7369
 
@@ -246,12 +246,9 @@ var InfiniteContextManager = class {
246
246
  0,
247
247
  contentStats.length - preserveCount
248
248
  );
249
- compressible = contentStats.filter((stat, index) => {
250
- if (this._isCompressedMessage(stat.message)) {
251
- return false;
252
- }
253
- return index < thresholdIndex;
254
- });
249
+ compressible = contentStats.filter(
250
+ (stat, index) => index < thresholdIndex
251
+ );
255
252
  if (compressible.length > 0) {
256
253
  break;
257
254
  }
@@ -272,10 +269,16 @@ var InfiniteContextManager = class {
272
269
  return null;
273
270
  }
274
271
  const compressor = this._ensureInfiniteContextChain(wrapper);
275
- const compressedSegments = [];
272
+ const chunkSummaries = [];
273
+ const previousSummaries = compressible.filter((stat) => this._isCompressedMessage(stat.message)).map(
274
+ (stat) => (0, import_string2.getMessageContent)(stat.message.content)?.trim() ?? ""
275
+ ).filter((text) => text.length > 0);
276
276
  for (let index = 0; index < chunkStats.length; index++) {
277
277
  const chunk = chunkStats[index];
278
- const chunkMessages = chunk.map((item) => item.message);
278
+ const chunkMessages = chunk.map((item) => item.message).filter((message) => !this._isCompressedMessage(message));
279
+ if (chunkMessages.length === 0) {
280
+ continue;
281
+ }
279
282
  const chunkText = this._formatChunkForCompression(chunkMessages);
280
283
  const compressedText = await compressor.compressChunk({
281
284
  chunk: chunkText,
@@ -284,40 +287,28 @@ var InfiniteContextManager = class {
284
287
  if (!compressedText) {
285
288
  continue;
286
289
  }
287
- compressedSegments.push({
290
+ chunkSummaries.push({
288
291
  content: compressedText,
289
292
  chunkIndex: index,
290
293
  chunkSize: chunkMessages.length
291
294
  });
292
295
  }
293
- if (compressedSegments.length === 0) {
296
+ if (chunkSummaries.length === 0 && previousSummaries.length === 0) {
297
+ return null;
298
+ }
299
+ const finalSummary = await this._buildFinalSummary(
300
+ compressor,
301
+ previousSummaries,
302
+ chunkSummaries
303
+ );
304
+ if (!finalSummary) {
294
305
  return null;
295
306
  }
296
- const aggregatedSummary = compressedSegments.map(
297
- (segment, idx) => `### Segment ${idx + 1}
298
- ${segment.content.trim()}`
299
- ).join("\n\n");
300
- const summaryMeta = {
301
- source: "infinite-context",
302
- segments: compressedSegments.length,
303
- segmentDetail: compressedSegments.map((segment, idx) => ({
304
- segment: idx + 1,
305
- chunkIndex: segment.chunkIndex,
306
- chunkSize: segment.chunkSize
307
- }))
308
- };
309
307
  const compressedMessages = [
310
308
  new import_messages.HumanMessage({
311
- content: `<infinite_context segments="${compressedSegments.length}">
312
- ${aggregatedSummary}
313
- </infinite_context>`,
309
+ content: finalSummary.content,
314
310
  name: "infinite_context",
315
- additional_kwargs: summaryMeta
316
- }),
317
- new import_messages.AIMessage({
318
- content: "Summary acknowledged. I will prioritise available tools when future turns involve these archived topics, and if no tools are available I will note the memory gap and ask the user to confirm the details.",
319
- name: "infinite_context_ack",
320
- additional_kwargs: summaryMeta
311
+ additional_kwargs: finalSummary.meta
321
312
  })
322
313
  ];
323
314
  const mergedMessages = [
@@ -384,33 +375,8 @@ ${aggregatedSummary}
384
375
  const role = message.getType().toUpperCase();
385
376
  const nameSuffix = message.name ? ` (${message.name})` : "";
386
377
  const content = (0, import_string2.getMessageContent)(message.content).trim();
387
- const extras = [];
388
- const aiMessage = message;
389
- if (Array.isArray(aiMessage.tool_calls) && aiMessage.tool_calls.length > 0) {
390
- const toolCalls = aiMessage.tool_calls.map((call) => {
391
- let args = "";
392
- try {
393
- args = JSON.stringify(call.args);
394
- } catch (error) {
395
- args = "[unserializable]";
396
- }
397
- return `${call.name} => ${args}`;
398
- }).join("; ");
399
- extras.push(`tool calls: ${toolCalls}`);
400
- }
401
- if (message.getType() === "tool") {
402
- const toolMessage = message;
403
- if (toolMessage.tool_call_id) {
404
- extras.push(`tool call id: ${toolMessage.tool_call_id}`);
405
- }
406
- if (toolMessage.name) {
407
- extras.push(`tool name: ${toolMessage.name}`);
408
- }
409
- }
410
- const extraText = extras.length > 0 ? `
411
- Meta: ${extras.join(", ")}` : "";
412
378
  return `[${role}${nameSuffix}]
413
- ${content || "(empty)"}${extraText}`;
379
+ ${content || "(empty)"}`;
414
380
  }).join("\n---\n");
415
381
  }
416
382
  _ensureInfiniteContextChain(wrapper) {
@@ -421,6 +387,64 @@ ${content || "(empty)"}${extraText}`;
421
387
  }
422
388
  return this._chain;
423
389
  }
390
+ async _buildFinalSummary(compressor, previousSummaries, chunkSummaries) {
391
+ const cleanedPrevious = previousSummaries.filter(
392
+ (text) => text.trim().length > 0
393
+ );
394
+ const cleanedChunks = chunkSummaries.filter(
395
+ (summary) => summary.content.trim().length > 0
396
+ );
397
+ if (cleanedPrevious.length === 0 && cleanedChunks.length === 0) {
398
+ return null;
399
+ }
400
+ if (cleanedPrevious.length === 0 && cleanedChunks.length === 1) {
401
+ return {
402
+ content: cleanedChunks[0].content.trim(),
403
+ meta: {
404
+ source: "infinite-context",
405
+ mergedSegments: 1,
406
+ previousSummaries: 0,
407
+ chunkDetail: [
408
+ {
409
+ chunkIndex: cleanedChunks[0].chunkIndex,
410
+ chunkSize: cleanedChunks[0].chunkSize
411
+ }
412
+ ]
413
+ }
414
+ };
415
+ }
416
+ const virtualTranscript = [];
417
+ if (cleanedPrevious.length > 0) {
418
+ virtualTranscript.push(
419
+ `Existing summary snapshot:
420
+ ${cleanedPrevious.join("\n\n")}`
421
+ );
422
+ }
423
+ cleanedChunks.forEach((chunk, index) => {
424
+ virtualTranscript.push(
425
+ `Recent segment ${index + 1} (${chunk.chunkSize} turns):
426
+ ${chunk.content}`
427
+ );
428
+ });
429
+ const mergedInput = virtualTranscript.join("\n\n---\n\n");
430
+ const refined = await compressor.compressChunk({
431
+ chunk: mergedInput,
432
+ conversationId: this.options.conversationId
433
+ });
434
+ const content = refined?.trim() || mergedInput;
435
+ return {
436
+ content,
437
+ meta: {
438
+ source: "infinite-context",
439
+ mergedSegments: cleanedChunks.length,
440
+ previousSummaries: cleanedPrevious.length,
441
+ chunkDetail: cleanedChunks.map((chunk) => ({
442
+ chunkIndex: chunk.chunkIndex,
443
+ chunkSize: chunk.chunkSize
444
+ }))
445
+ }
446
+ };
447
+ }
424
448
  };
425
449
 
426
450
  // src/llm-core/chat/app.ts
@@ -20,15 +20,12 @@ import { ChatLunaChatModel } from "koishi-plugin-chatluna/llm-core/platform/mode
20
20
  import {
21
21
  ModelCapabilities
22
22
  } from "koishi-plugin-chatluna/llm-core/platform/types";
23
- import { AIMessage as AIMessage2, ToolMessage as ToolMessage2 } from "@langchain/core/messages";
23
+ import { AIMessage, ToolMessage } from "@langchain/core/messages";
24
24
  import { getMessageContent as getMessageContent3 } from "koishi-plugin-chatluna/utils/string";
25
25
  import { computed } from "@vue/reactivity";
26
26
 
27
27
  // src/llm-core/chat/infinite_context.ts
28
- import {
29
- AIMessage,
30
- HumanMessage
31
- } from "@langchain/core/messages";
28
+ import { HumanMessage } from "@langchain/core/messages";
32
29
  import { getMessageContent as getMessageContent2 } from "koishi-plugin-chatluna/utils/string";
33
30
  import { logger } from "koishi-plugin-chatluna";
34
31
 
@@ -243,12 +240,9 @@ var InfiniteContextManager = class {
243
240
  0,
244
241
  contentStats.length - preserveCount
245
242
  );
246
- compressible = contentStats.filter((stat, index) => {
247
- if (this._isCompressedMessage(stat.message)) {
248
- return false;
249
- }
250
- return index < thresholdIndex;
251
- });
243
+ compressible = contentStats.filter(
244
+ (stat, index) => index < thresholdIndex
245
+ );
252
246
  if (compressible.length > 0) {
253
247
  break;
254
248
  }
@@ -269,10 +263,16 @@ var InfiniteContextManager = class {
269
263
  return null;
270
264
  }
271
265
  const compressor = this._ensureInfiniteContextChain(wrapper);
272
- const compressedSegments = [];
266
+ const chunkSummaries = [];
267
+ const previousSummaries = compressible.filter((stat) => this._isCompressedMessage(stat.message)).map(
268
+ (stat) => getMessageContent2(stat.message.content)?.trim() ?? ""
269
+ ).filter((text) => text.length > 0);
273
270
  for (let index = 0; index < chunkStats.length; index++) {
274
271
  const chunk = chunkStats[index];
275
- const chunkMessages = chunk.map((item) => item.message);
272
+ const chunkMessages = chunk.map((item) => item.message).filter((message) => !this._isCompressedMessage(message));
273
+ if (chunkMessages.length === 0) {
274
+ continue;
275
+ }
276
276
  const chunkText = this._formatChunkForCompression(chunkMessages);
277
277
  const compressedText = await compressor.compressChunk({
278
278
  chunk: chunkText,
@@ -281,40 +281,28 @@ var InfiniteContextManager = class {
281
281
  if (!compressedText) {
282
282
  continue;
283
283
  }
284
- compressedSegments.push({
284
+ chunkSummaries.push({
285
285
  content: compressedText,
286
286
  chunkIndex: index,
287
287
  chunkSize: chunkMessages.length
288
288
  });
289
289
  }
290
- if (compressedSegments.length === 0) {
290
+ if (chunkSummaries.length === 0 && previousSummaries.length === 0) {
291
+ return null;
292
+ }
293
+ const finalSummary = await this._buildFinalSummary(
294
+ compressor,
295
+ previousSummaries,
296
+ chunkSummaries
297
+ );
298
+ if (!finalSummary) {
291
299
  return null;
292
300
  }
293
- const aggregatedSummary = compressedSegments.map(
294
- (segment, idx) => `### Segment ${idx + 1}
295
- ${segment.content.trim()}`
296
- ).join("\n\n");
297
- const summaryMeta = {
298
- source: "infinite-context",
299
- segments: compressedSegments.length,
300
- segmentDetail: compressedSegments.map((segment, idx) => ({
301
- segment: idx + 1,
302
- chunkIndex: segment.chunkIndex,
303
- chunkSize: segment.chunkSize
304
- }))
305
- };
306
301
  const compressedMessages = [
307
302
  new HumanMessage({
308
- content: `<infinite_context segments="${compressedSegments.length}">
309
- ${aggregatedSummary}
310
- </infinite_context>`,
303
+ content: finalSummary.content,
311
304
  name: "infinite_context",
312
- additional_kwargs: summaryMeta
313
- }),
314
- new AIMessage({
315
- content: "Summary acknowledged. I will prioritise available tools when future turns involve these archived topics, and if no tools are available I will note the memory gap and ask the user to confirm the details.",
316
- name: "infinite_context_ack",
317
- additional_kwargs: summaryMeta
305
+ additional_kwargs: finalSummary.meta
318
306
  })
319
307
  ];
320
308
  const mergedMessages = [
@@ -381,33 +369,8 @@ ${aggregatedSummary}
381
369
  const role = message.getType().toUpperCase();
382
370
  const nameSuffix = message.name ? ` (${message.name})` : "";
383
371
  const content = getMessageContent2(message.content).trim();
384
- const extras = [];
385
- const aiMessage = message;
386
- if (Array.isArray(aiMessage.tool_calls) && aiMessage.tool_calls.length > 0) {
387
- const toolCalls = aiMessage.tool_calls.map((call) => {
388
- let args = "";
389
- try {
390
- args = JSON.stringify(call.args);
391
- } catch (error) {
392
- args = "[unserializable]";
393
- }
394
- return `${call.name} => ${args}`;
395
- }).join("; ");
396
- extras.push(`tool calls: ${toolCalls}`);
397
- }
398
- if (message.getType() === "tool") {
399
- const toolMessage = message;
400
- if (toolMessage.tool_call_id) {
401
- extras.push(`tool call id: ${toolMessage.tool_call_id}`);
402
- }
403
- if (toolMessage.name) {
404
- extras.push(`tool name: ${toolMessage.name}`);
405
- }
406
- }
407
- const extraText = extras.length > 0 ? `
408
- Meta: ${extras.join(", ")}` : "";
409
372
  return `[${role}${nameSuffix}]
410
- ${content || "(empty)"}${extraText}`;
373
+ ${content || "(empty)"}`;
411
374
  }).join("\n---\n");
412
375
  }
413
376
  _ensureInfiniteContextChain(wrapper) {
@@ -418,6 +381,64 @@ ${content || "(empty)"}${extraText}`;
418
381
  }
419
382
  return this._chain;
420
383
  }
384
+ async _buildFinalSummary(compressor, previousSummaries, chunkSummaries) {
385
+ const cleanedPrevious = previousSummaries.filter(
386
+ (text) => text.trim().length > 0
387
+ );
388
+ const cleanedChunks = chunkSummaries.filter(
389
+ (summary) => summary.content.trim().length > 0
390
+ );
391
+ if (cleanedPrevious.length === 0 && cleanedChunks.length === 0) {
392
+ return null;
393
+ }
394
+ if (cleanedPrevious.length === 0 && cleanedChunks.length === 1) {
395
+ return {
396
+ content: cleanedChunks[0].content.trim(),
397
+ meta: {
398
+ source: "infinite-context",
399
+ mergedSegments: 1,
400
+ previousSummaries: 0,
401
+ chunkDetail: [
402
+ {
403
+ chunkIndex: cleanedChunks[0].chunkIndex,
404
+ chunkSize: cleanedChunks[0].chunkSize
405
+ }
406
+ ]
407
+ }
408
+ };
409
+ }
410
+ const virtualTranscript = [];
411
+ if (cleanedPrevious.length > 0) {
412
+ virtualTranscript.push(
413
+ `Existing summary snapshot:
414
+ ${cleanedPrevious.join("\n\n")}`
415
+ );
416
+ }
417
+ cleanedChunks.forEach((chunk, index) => {
418
+ virtualTranscript.push(
419
+ `Recent segment ${index + 1} (${chunk.chunkSize} turns):
420
+ ${chunk.content}`
421
+ );
422
+ });
423
+ const mergedInput = virtualTranscript.join("\n\n---\n\n");
424
+ const refined = await compressor.compressChunk({
425
+ chunk: mergedInput,
426
+ conversationId: this.options.conversationId
427
+ });
428
+ const content = refined?.trim() || mergedInput;
429
+ return {
430
+ content,
431
+ meta: {
432
+ source: "infinite-context",
433
+ mergedSegments: cleanedChunks.length,
434
+ previousSummaries: cleanedPrevious.length,
435
+ chunkDetail: cleanedChunks.map((chunk) => ({
436
+ chunkIndex: chunk.chunkIndex,
437
+ chunkSize: chunk.chunkSize
438
+ }))
439
+ }
440
+ };
441
+ }
421
442
  };
422
443
 
423
444
  // src/llm-core/chat/app.ts
@@ -510,7 +531,7 @@ var ChatInterface = class {
510
531
  maxToken: this.preset?.value?.config?.maxOutputToken
511
532
  });
512
533
  const responseMessage = response.message;
513
- const displayResponse = new AIMessage2({
534
+ const displayResponse = new AIMessage({
514
535
  content: responseMessage.content
515
536
  });
516
537
  displayResponse.additional_kwargs = responseMessage.additional_kwargs;
@@ -536,7 +557,7 @@ var ChatInterface = class {
536
557
  const intermediateSteps = response["parallelIntermediateSteps"];
537
558
  for (const parallelSteps of intermediateSteps) {
538
559
  await this.chatHistory.addMessage(
539
- new AIMessage2({
560
+ new AIMessage({
540
561
  content: "",
541
562
  tool_calls: parallelSteps.map((step) => ({
542
563
  id: step.action.toolCallId,
@@ -547,7 +568,7 @@ var ChatInterface = class {
547
568
  );
548
569
  for (const step of parallelSteps) {
549
570
  await this.chatHistory.addMessage(
550
- new ToolMessage2({
571
+ new ToolMessage({
551
572
  content: step.observation,
552
573
  tool_call_id: step.action.toolCallId,
553
574
  name: step.action.tool
@@ -19,4 +19,5 @@ export declare class InfiniteContextManager {
19
19
  private _countMessagesTokens;
20
20
  private _formatChunkForCompression;
21
21
  private _ensureInfiniteContextChain;
22
+ private _buildFinalSummary;
22
23
  }
@@ -217,6 +217,7 @@ var ChatLunaChatModel = class extends import_chat_models.BaseChatModel {
217
217
  "logitBias",
218
218
  "id",
219
219
  "variables_hide",
220
+ "overrideRequestParams",
220
221
  "stream",
221
222
  "tools"
222
223
  ];
@@ -233,6 +234,10 @@ var ChatLunaChatModel = class extends import_chat_models.BaseChatModel {
233
234
  if (maxTokenLimit != null && maxTokenLimit >= this.getModelMaxContextSize()) {
234
235
  maxTokenLimit = this.getModelMaxContextSize();
235
236
  }
237
+ let id = options?.id ?? this._options.id;
238
+ if (!id) {
239
+ id = options?.variables_hide?.["built"]?.["conversationId"];
240
+ }
236
241
  return {
237
242
  model: modelName,
238
243
  temperature: options?.temperature ?? this._options.temperature,
@@ -243,11 +248,12 @@ var ChatLunaChatModel = class extends import_chat_models.BaseChatModel {
243
248
  logitBias: options?.logitBias ?? this._options.logitBias,
244
249
  maxTokens: options?.maxTokens ?? this._options.maxTokens,
245
250
  maxTokenLimit,
246
- variables: options?.["variables_hide"] ?? {},
251
+ variables: options?.["variables_hide"] ?? options?.["variables"] ?? {},
252
+ overrideRequestParams: options?.overrideRequestParams ?? this._options.overrideRequestParams ?? {},
247
253
  stop: options?.stop ?? this._options.stop,
248
254
  stream: options?.stream ?? this._options.stream,
249
255
  tools: options?.tools ?? this._options.tools,
250
- id: options?.id ?? this._options.id,
256
+ id,
251
257
  signal: options?.signal ?? this._options.signal,
252
258
  timeout: options?.timeout ?? this._options.timeout
253
259
  };
@@ -37,6 +37,10 @@ export interface ChatLunaModelCallOptions extends BaseChatModelCallOptions {
37
37
  tool_choice?: string;
38
38
  variables?: Record<string, any>;
39
39
  variables_hide?: Record<string, any>;
40
+ /**
41
+ * Override request params for this request only.
42
+ */
43
+ overrideRequestParams?: Record<string, any>;
40
44
  }
41
45
  export interface ChatLunaModelInput extends ChatLunaModelCallOptions {
42
46
  llmType?: string;
@@ -199,6 +199,7 @@ var ChatLunaChatModel = class extends BaseChatModel {
199
199
  "logitBias",
200
200
  "id",
201
201
  "variables_hide",
202
+ "overrideRequestParams",
202
203
  "stream",
203
204
  "tools"
204
205
  ];
@@ -215,6 +216,10 @@ var ChatLunaChatModel = class extends BaseChatModel {
215
216
  if (maxTokenLimit != null && maxTokenLimit >= this.getModelMaxContextSize()) {
216
217
  maxTokenLimit = this.getModelMaxContextSize();
217
218
  }
219
+ let id = options?.id ?? this._options.id;
220
+ if (!id) {
221
+ id = options?.variables_hide?.["built"]?.["conversationId"];
222
+ }
218
223
  return {
219
224
  model: modelName,
220
225
  temperature: options?.temperature ?? this._options.temperature,
@@ -225,11 +230,12 @@ var ChatLunaChatModel = class extends BaseChatModel {
225
230
  logitBias: options?.logitBias ?? this._options.logitBias,
226
231
  maxTokens: options?.maxTokens ?? this._options.maxTokens,
227
232
  maxTokenLimit,
228
- variables: options?.["variables_hide"] ?? {},
233
+ variables: options?.["variables_hide"] ?? options?.["variables"] ?? {},
234
+ overrideRequestParams: options?.overrideRequestParams ?? this._options.overrideRequestParams ?? {},
229
235
  stop: options?.stop ?? this._options.stop,
230
236
  stream: options?.stream ?? this._options.stream,
231
237
  tools: options?.tools ?? this._options.tools,
232
- id: options?.id ?? this._options.id,
238
+ id,
233
239
  signal: options?.signal ?? this._options.signal,
234
240
  timeout: options?.timeout ?? this._options.timeout
235
241
  };
@@ -330,6 +330,7 @@ function getSystemPromptVariables(session, config, room) {
330
330
  group_id: session.guildId ?? session.event?.guild?.id,
331
331
  group_name: session.event?.guild?.name || session.guildId,
332
332
  user_id: session.author?.user?.id ?? session.event?.user?.id ?? session.userId ?? "0",
333
+ platform: session.platform,
333
334
  user: getNotEmptyString(
334
335
  session.author?.nick,
335
336
  session.author?.name,
@@ -338,6 +339,7 @@ function getSystemPromptVariables(session, config, room) {
338
339
  ),
339
340
  built: {
340
341
  preset: room.preset,
342
+ platform: session.platform,
341
343
  conversationId: room.conversationId
342
344
  },
343
345
  noop: "",
@@ -45,9 +45,11 @@ export declare function getSystemPromptVariables(session: Session, config: Confi
45
45
  group_id: string;
46
46
  group_name: string;
47
47
  user_id: string;
48
+ platform: string;
48
49
  user: string;
49
50
  built: {
50
51
  preset: string;
52
+ platform: string;
51
53
  conversationId: string;
52
54
  };
53
55
  noop: string;
@@ -277,6 +277,7 @@ function getSystemPromptVariables(session, config, room) {
277
277
  group_id: session.guildId ?? session.event?.guild?.id,
278
278
  group_name: session.event?.guild?.name || session.guildId,
279
279
  user_id: session.author?.user?.id ?? session.event?.user?.id ?? session.userId ?? "0",
280
+ platform: session.platform,
280
281
  user: getNotEmptyString(
281
282
  session.author?.nick,
282
283
  session.author?.name,
@@ -285,6 +286,7 @@ function getSystemPromptVariables(session, config, room) {
285
286
  ),
286
287
  built: {
287
288
  preset: room.preset,
289
+ platform: session.platform,
288
290
  conversationId: room.conversationId
289
291
  },
290
292
  noop: "",
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.3",
4
+ "version": "1.3.5",
5
5
  "main": "lib/index.cjs",
6
6
  "module": "lib/index.mjs",
7
7
  "typings": "lib/index.d.ts",