koishi-plugin-chatluna 1.4.0 → 1.4.2

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 CHANGED
@@ -34,14 +34,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
34
34
  // src/locales/zh-CN.schema.yml
35
35
  var require_zh_CN_schema = __commonJS({
36
36
  "src/locales/zh-CN.schema.yml"(exports2, module2) {
37
- module2.exports = { $inner: [{ $desc: "bot 配置", botNames: "设置 bot 的名称。(只有第一个名称是实际的 bot 名称,其他名称仅用于触发对话)", isNickname: "是否允许在开头匹配 bot 配置中的昵称来触发对话。", isNickNameWithContent: "是否允许在对话内容里任意匹配 bot 配置中的昵称来触发对话。" }, { $desc: "对话行为选项", allowPrivate: "是否允许在私聊中触发对话。", allowAtReply: "是否允许通过 @ bot 来触发对话。", allowQuoteReply: "是否允许通过引用 bot 的消息来触发对话。", privateChatWithoutCommand: "在私聊中是否允许无需命令直接与 bot 对话。", allowConversationTriggerPrefix: "是否允许使用会话的标题前缀触发对话。注意:启用此选项可能会显著影响 ChatLuna 的性能,建议配合过滤器仅在特定群组中启用。", randomReplyFrequency: "设置随机回复的频率。", includeQuoteReply: "是否在向模型的请求内容中添加被引用的消息内容", attachForwardMsgIdToContext: "是否将合并转发聊天记录消息的 ID 附加到上下文中。启用后,检测到聊天记录会额外追加一条 [聊天记录] 消息。", autoUpdateConversationModel: "是否允许自动把会话更新为全局默认默认模型。" }, { isForwardMsg: "是否以合并消息的形式发送 bot 的回复。", forwardMsgMinLength: "合并消息的最小应用长度。为 0 则总是应用。设置大于 0 时,只有发送的文本大于此长度才会转为合并消息。" }, { isReplyWithAt: "当 bot 回复时,是否引用原消息", replyQuoteThreshold: "引用原消息的最小响应时长。为 0 则总是应用。设置大于 0 时,只有响应耗时大于此时长才会引用原消息。" }, { $desc: "对话响应选项", sendThinkingMessage: "是否在请求处理过程中发送等待消息。", sendThinkingMessageTimeout: "设置在模型开始响应前,等待多少毫秒后发送等待消息。", thinkingMessage: "自定义等待消息的内容。", msgCooldown: "设置全局消息冷却时间(单位:秒),用于防止适配器被过于频繁地调用。", messageQueue: "设置是否启用消息队列。启用后当用户发送了多条消息,并且模型未响应初始消息时,会将消息缓存合并成一条消息,并等待模型响应后再发送。", messageQueueDelay: "设置消息队列的延迟时间(单位:秒)。为 0 则不启用延迟。开启延迟后,会等待指定时间后才发送消息给模型,如果在此期间内存在未处理的消息,则将消息缓存合并成多条消息发送给模型。", agentTaskAutoWakeup: "是否允许后台代理任务完成后自动唤醒所在对话。", showThoughtMessage: "在使用 Agent 模式或思考模型时,是否显示思考过程。" }, { $desc: "消息渲染选项", outputMode: { $desc: "选择消息回复的渲染输出模式。" }, splitMessage: { $desc: "设置消息分割发送方式。非流式和流式回复都会按此选项切割。", $inner: ["不切割", "按标点切割", "按段落切割"] }, censor: "是否启用文本审核服务(需要安装 censor 服务)。", rawOnCensor: "是否在 Post Handler 被触发时,将原始消息发送给模型。", streamResponse: "是否启用流式响应。启用后,bot 会在生成回复的过程中就开始发送消息,而不是等待完全生成后发送。" }, { $desc: "黑名单选项", blackList: { $desc: "设置黑名单列表。请谨慎使用,只对需要拉黑的用户或群启用。1 表示启用黑名单,0 表示不启用黑名单。默认值为 0。" } }, { $desc: "历史记录选项", infiniteContext: "启用「无限上下文」,当对话接近模型的上下文上限时自动压缩旧消息,保留关键话题和指令并丢弃无关内容。", infiniteContextThreshold: "设置无限上下文的触发阈值(百分比)。当对话历史的 token 数达到模型上下文上限的该百分比时,将触发压缩。", autoArchive: "是否自动归档长期未使用的会话,而不是继续保留旧的房间状态。", autoArchiveTimeout: "设置自动归档未使用会话的时间阈值(单位:秒)。", autoPurgeArchive: "是否在归档会话超过保留时间后自动彻底删除。", autoPurgeArchiveTimeout: "设置归档会话被自动删除前的保留时间(单位:秒)。" }, { $desc: "模型选项", defaultEmbeddings: "设置默认使用的嵌入模型。", defaultVectorStore: "设置默认使用的向量数据库。" }, { $desc: "会话路由默认配置", defaultGroupRouteMode: { $desc: "设置群聊场景下默认的会话路由模式,决定群成员是共享同一路由还是各自拥有独立路由,也会影响预设分流。", $inner: ["群共享会话", "成员独立会话"] }, defaultChatMode: "设置默认的聊天模式。", defaultModel: "设置默认使用的聊天模型。", defaultPreset: "设置默认使用的聊天预设。", enablePresetKeywordTrigger: "是否允许通过预设关键词切换预设。" }, { $desc: "杂项", errorTemplate: "设置错误提示消息的模板(此设置在未来版本中可能会有变更)。", voiceSpeakId: "设置使用 vits 服务时的默认发音人 ID。", isLog: "是否启用调试模式。" }, { isProxy: { $desc: "是否启用代理。启用后,ChatLuna 全家桶插件的网络请求将使用此代理。", $inner: [true] }, proxyAddress: "网络请求的代理地址。填写后,ChatLuna 相关插件的网络服务将使用此代理地址。若为空,将尝试使用 Koishi 全局配置中的代理设置。" }] };
37
+ module2.exports = { $inner: [{ $desc: "bot 配置", botNames: "设置 bot 的名称。(只有第一个名称是实际的 bot 名称,其他名称仅用于触发对话)", isNickname: "是否允许在开头匹配 bot 配置中的昵称来触发对话。", isNickNameWithContent: "是否允许在对话内容里任意匹配 bot 配置中的昵称来触发对话。" }, { $desc: "对话行为选项", allowPrivate: "是否允许在私聊中触发对话。", allowAtReply: "是否允许通过 @ bot 来触发对话。", allowQuoteReply: "是否允许通过引用 bot 的消息来触发对话。", privateChatWithoutCommand: "在私聊中是否允许无需命令直接与 bot 对话。", allowConversationTriggerPrefix: "是否允许使用会话的标题前缀触发对话。注意:启用此选项可能会显著影响 ChatLuna 的性能,建议配合过滤器仅在特定群组中启用。", randomReplyFrequency: "设置随机回复的频率。", includeQuoteReply: "是否在向模型的请求内容中添加被引用的消息内容", attachForwardMsgIdToContext: "是否将合并转发聊天记录消息的 ID 附加到上下文中。启用后,检测到聊天记录会额外追加一条 [聊天记录] 消息。", autoUpdateConversationModel: "是否允许自动把会话更新为全局默认默认模型。" }, { isForwardMsg: "是否以合并消息的形式发送 bot 的回复。", forwardMsgMinLength: "合并消息的最小应用长度。为 0 则总是应用。设置大于 0 时,只有发送的文本大于此长度才会转为合并消息。" }, { isReplyWithAt: "当 bot 回复时,是否引用原消息", replyQuoteThreshold: "引用原消息的最小响应时长。为 0 则总是应用。设置大于 0 时,只有响应耗时大于此时长才会引用原消息。" }, { $desc: "对话响应选项", sendThinkingMessage: "是否在请求处理过程中发送等待消息。", sendThinkingMessageTimeout: "设置在模型开始响应前,等待多少毫秒后发送等待消息。", thinkingMessage: "自定义等待消息的内容。", msgCooldown: "设置全局消息冷却时间(单位:秒),用于防止适配器被过于频繁地调用。", messageQueue: "设置是否启用消息队列。启用后当用户发送了多条消息,并且模型未响应初始消息时,会将消息缓存合并成一条消息,并等待模型响应后再发送。", messageQueueDelay: "设置消息队列的延迟时间(单位:秒)。为 0 则不启用延迟。开启延迟后,会等待指定时间后才发送消息给模型,如果在此期间内存在未处理的消息,则将消息缓存合并成多条消息发送给模型。", agentTaskAutoWakeup: "是否允许后台代理任务完成后自动唤醒所在对话。", showThoughtMessage: "在使用 Agent 模式或思考模型时,是否显示思考过程。" }, { $desc: "消息渲染选项", outputMode: { $desc: "选择消息回复的渲染输出模式。" }, splitMessage: { $desc: "设置消息分割发送方式。非流式和流式回复都会按此选项切割。", $inner: ["不切割", "按标点切割", "按段落切割"] }, censor: "是否启用文本审核服务(需要安装 censor 服务)。启用后会等待完整回复生成并审核,再进行渲染、分段和发送。", rawOnCensor: "是否在 Post Handler 被触发时,将原始消息发送给模型。", streamResponse: "是否启用流式响应。启用后,bot 会在生成回复的过程中就开始发送消息;若启用了 censor 或预设中的 postHandler.censor,则等待完整回复审核后再发送。" }, { $desc: "黑名单选项", blackList: { $desc: "设置黑名单列表。请谨慎使用,只对需要拉黑的用户或群启用。1 表示启用黑名单,0 表示不启用黑名单。默认值为 0。" } }, { $desc: "历史记录选项", infiniteContext: "启用「无限上下文」,当对话接近模型的上下文上限时自动压缩旧消息,保留关键话题和指令并丢弃无关内容。", infiniteContextThreshold: "设置无限上下文的触发阈值(百分比)。当对话历史的 token 数达到模型上下文上限的该百分比时,将触发压缩。", autoArchive: "是否自动归档长期未使用的会话,而不是继续保留旧的房间状态。", autoArchiveTimeout: "设置自动归档未使用会话的时间阈值(单位:秒)。", autoPurgeArchive: "是否在归档会话超过保留时间后自动彻底删除。", autoPurgeArchiveTimeout: "设置归档会话被自动删除前的保留时间(单位:秒)。" }, { $desc: "模型选项", defaultEmbeddings: "设置默认使用的嵌入模型。", defaultVectorStore: "设置默认使用的向量数据库。" }, { $desc: "会话路由默认配置", defaultGroupRouteMode: { $desc: "设置群聊场景下默认的会话路由模式,决定群成员是共享同一路由还是各自拥有独立路由,也会影响预设分流。", $inner: ["群共享会话", "成员独立会话"] }, defaultChatMode: "设置默认的聊天模式。", defaultModel: "设置默认使用的聊天模型。", defaultPreset: "设置默认使用的聊天预设。", enablePresetKeywordTrigger: "是否允许通过预设关键词切换预设。" }, { $desc: "杂项", errorTemplate: "设置错误提示消息的模板(此设置在未来版本中可能会有变更)。", voiceSpeakId: "设置使用 vits 服务时的默认发音人 ID。", isLog: "是否启用调试模式。" }, { isProxy: { $desc: "是否启用代理。启用后,ChatLuna 全家桶插件的网络请求将使用此代理。", $inner: [true] }, proxyAddress: "网络请求的代理地址。填写后,ChatLuna 相关插件的网络服务将使用此代理地址。若为空,将尝试使用 Koishi 全局配置中的代理设置。" }] };
38
38
  }
39
39
  });
40
40
 
41
41
  // src/locales/en-US.schema.yml
42
42
  var require_en_US_schema = __commonJS({
43
43
  "src/locales/en-US.schema.yml"(exports2, module2) {
44
- module2.exports = { $inner: [{ $desc: "Bot Configuration", botNames: "Set the bot's name. (Only the first name is the actual bot name; other names are only used to trigger conversations.)", isNickname: "Allow matching bot nickname at the beginning of a message to trigger a conversation.", isNickNameWithContent: "Allow matching bot nickname anywhere in the message content to trigger a conversation." }, { $desc: "Conversation Behavior", allowPrivate: "Enable private chat conversations.", allowAtReply: "Enable @mention triggering.", allowQuoteReply: "Enable quote triggering.", privateChatWithoutCommand: "Enable direct conversation in private chats without commands.", allowConversationTriggerPrefix: "Enable conversation title prefix triggering. Note: May impact performance significantly. Recommended for use with filters in specific groups only.", randomReplyFrequency: "Set random reply frequency (0-100, where 0 means never and 100 means always).", includeQuoteReply: "Include quoted message content in requests sent to the model.", attachForwardMsgIdToContext: 'Attach forward message record IDs to context. When enabled, a "[聊天记录]" marker message will be appended if forward records are detected.', autoUpdateConversationModel: "Allow conversations to be automatically updated to the global default model." }, { isForwardMsg: "Send bot replies as forwarded messages.", forwardMsgMinLength: "Set minimum length of forwarded messages (characters)." }, { isReplyWithAt: "Quote the original message when the bot replies.", replyQuoteThreshold: "Minimum response time required to quote the original message. Set to 0 to always apply. When greater than 0, the original message will only be quoted if the response time exceeds this threshold." }, { $desc: "Response Options", sendThinkingMessage: "Send waiting message during processing.", sendThinkingMessageTimeout: "Set timeout (ms) for waiting message dispatch.", thinkingMessage: "Customize waiting message content.", msgCooldown: "Set global message cooldown (seconds) to limit adapter calls.", messageQueue: "Enable message queue. When enabled, if a user sends multiple messages before the model responds to the initial message, the messages will be cached and merged into one message, then sent after the model responds.", messageQueueDelay: "Set message queue delay time (seconds). Set to 0 to disable delay. When delay is enabled, the system will wait for the specified time before sending messages to the model. If there are unprocessed messages during this period, they will be cached and merged into multiple messages to send to the model.", agentTaskAutoWakeup: "Allow background agent tasks to wake up their conversations automatically when completed.", showThoughtMessage: "Display the thinking process when using Agent mode or a reasoning model." }, { $desc: "Message Rendering", outputMode: { $desc: "Select message reply rendering mode." }, splitMessage: { $desc: "Split outgoing messages. Applies to both streaming and non-streaming replies.", $inner: ["Do not split", "Split by punctuation", "Split by paragraph"] }, censor: "Enable text moderation (requires censor service).", rawOnCensor: "Whether to send the raw message to the model when the Post Handler is triggered.", streamResponse: "Enable streaming responses so the bot starts sending content while generating the reply instead of waiting for completion." }, { $desc: "Blacklist Management", blackList: "Configure blacklist. Use cautiously to avoid unintended blocking. The number 1 indicates enabled blacklist. Set to zero value to unenable blacklist." }, { $desc: "History Management", infiniteContext: "Enable automatic Infinite Context compression when history nears the model limit. Preserves critical topics and instructions while discarding noise.", infiniteContextThreshold: "Set the threshold (percentage) for triggering Infinite Context compression. Compression will be triggered when the token count of conversation history reaches this percentage of the model's context limit.", autoArchive: "Enable automatic archiving of inactive conversations instead of keeping legacy room state alive.", autoArchiveTimeout: "Set inactivity threshold for conversation archiving in seconds.", autoPurgeArchive: "Enable automatic deletion of archived conversations after the purge timeout.", autoPurgeArchiveTimeout: "Set how long archived conversations are retained before automatic purge in seconds." }, { $desc: "Model Configuration", defaultEmbeddings: "Set default embedding model.", defaultVectorStore: "Set default vector database." }, { $desc: "Conversation Routing Defaults", defaultGroupRouteMode: { $desc: "Set the default conversation route mode for group chats. This controls whether group members share one conversation route or get personal routes, including preset-lane routes.", $inner: ["Shared group conversation", "Personal conversation per member"] }, defaultChatMode: "Set default chat mode.", defaultModel: "Set default chat model.", defaultPreset: "Set default chat preset.", enablePresetKeywordTrigger: "Allow switching presets via preset keywords." }, { $desc: "Miscellaneous", errorTemplate: "Set error prompt message template (subject to change).", voiceSpeakId: "Set default speaker ID for vits service.", isLog: "Enable debug mode." }, { isProxy: { $desc: "Enable proxy for ChatLuna family plugin network requests.", $inner: [true] }, proxyAddress: "Set proxy address for network requests. Falls back to Koishi global proxy settings if cleared." }] };
44
+ module2.exports = { $inner: [{ $desc: "Bot Configuration", botNames: "Set the bot's name. (Only the first name is the actual bot name; other names are only used to trigger conversations.)", isNickname: "Allow matching bot nickname at the beginning of a message to trigger a conversation.", isNickNameWithContent: "Allow matching bot nickname anywhere in the message content to trigger a conversation." }, { $desc: "Conversation Behavior", allowPrivate: "Enable private chat conversations.", allowAtReply: "Enable @mention triggering.", allowQuoteReply: "Enable quote triggering.", privateChatWithoutCommand: "Enable direct conversation in private chats without commands.", allowConversationTriggerPrefix: "Enable conversation title prefix triggering. Note: May impact performance significantly. Recommended for use with filters in specific groups only.", randomReplyFrequency: "Set random reply frequency (0-100, where 0 means never and 100 means always).", includeQuoteReply: "Include quoted message content in requests sent to the model.", attachForwardMsgIdToContext: 'Attach forward message record IDs to context. When enabled, a "[聊天记录]" marker message will be appended if forward records are detected.', autoUpdateConversationModel: "Allow conversations to be automatically updated to the global default model." }, { isForwardMsg: "Send bot replies as forwarded messages.", forwardMsgMinLength: "Set minimum length of forwarded messages (characters)." }, { isReplyWithAt: "Quote the original message when the bot replies.", replyQuoteThreshold: "Minimum response time required to quote the original message. Set to 0 to always apply. When greater than 0, the original message will only be quoted if the response time exceeds this threshold." }, { $desc: "Response Options", sendThinkingMessage: "Send waiting message during processing.", sendThinkingMessageTimeout: "Set timeout (ms) for waiting message dispatch.", thinkingMessage: "Customize waiting message content.", msgCooldown: "Set global message cooldown (seconds) to limit adapter calls.", messageQueue: "Enable message queue. When enabled, if a user sends multiple messages before the model responds to the initial message, the messages will be cached and merged into one message, then sent after the model responds.", messageQueueDelay: "Set message queue delay time (seconds). Set to 0 to disable delay. When delay is enabled, the system will wait for the specified time before sending messages to the model. If there are unprocessed messages during this period, they will be cached and merged into multiple messages to send to the model.", agentTaskAutoWakeup: "Allow background agent tasks to wake up their conversations automatically when completed.", showThoughtMessage: "Display the thinking process when using Agent mode or a reasoning model." }, { $desc: "Message Rendering", outputMode: { $desc: "Select message reply rendering mode." }, splitMessage: { $desc: "Split outgoing messages. Applies to both streaming and non-streaming replies.", $inner: ["Do not split", "Split by punctuation", "Split by paragraph"] }, censor: "Enable text moderation (requires censor service). Waits for the complete reply and moderates it before rendering, splitting, and sending.", rawOnCensor: "Whether to send the raw message to the model when the Post Handler is triggered.", streamResponse: "Enable sending content while generating the reply. If censor or the preset's postHandler.censor is enabled, waits for complete reply moderation before sending." }, { $desc: "Blacklist Management", blackList: "Configure blacklist. Use cautiously to avoid unintended blocking. The number 1 indicates enabled blacklist. Set to zero value to unenable blacklist." }, { $desc: "History Management", infiniteContext: "Enable automatic Infinite Context compression when history nears the model limit. Preserves critical topics and instructions while discarding noise.", infiniteContextThreshold: "Set the threshold (percentage) for triggering Infinite Context compression. Compression will be triggered when the token count of conversation history reaches this percentage of the model's context limit.", autoArchive: "Enable automatic archiving of inactive conversations instead of keeping legacy room state alive.", autoArchiveTimeout: "Set inactivity threshold for conversation archiving in seconds.", autoPurgeArchive: "Enable automatic deletion of archived conversations after the purge timeout.", autoPurgeArchiveTimeout: "Set how long archived conversations are retained before automatic purge in seconds." }, { $desc: "Model Configuration", defaultEmbeddings: "Set default embedding model.", defaultVectorStore: "Set default vector database." }, { $desc: "Conversation Routing Defaults", defaultGroupRouteMode: { $desc: "Set the default conversation route mode for group chats. This controls whether group members share one conversation route or get personal routes, including preset-lane routes.", $inner: ["Shared group conversation", "Personal conversation per member"] }, defaultChatMode: "Set default chat mode.", defaultModel: "Set default chat model.", defaultPreset: "Set default chat preset.", enablePresetKeywordTrigger: "Allow switching presets via preset keywords." }, { $desc: "Miscellaneous", errorTemplate: "Set error prompt message template (subject to change).", voiceSpeakId: "Set default speaker ID for vits service.", isLog: "Enable debug mode." }, { isProxy: { $desc: "Enable proxy for ChatLuna family plugin network requests.", $inner: [true] }, proxyAddress: "Set proxy address for network requests. Falls back to Koishi global proxy settings if cleared." }] };
45
45
  }
46
46
  });
47
47
 
@@ -78,9 +78,9 @@ __export(index_exports, {
78
78
  usage: () => usage
79
79
  });
80
80
  module.exports = __toCommonJS(index_exports);
81
- var import_koishi26 = require("koishi");
81
+ var import_koishi27 = require("koishi");
82
82
  var import_chat2 = require("koishi-plugin-chatluna/services/chat");
83
- var import_koishi27 = require("koishi-plugin-chatluna/utils/koishi");
83
+ var import_koishi28 = require("koishi-plugin-chatluna/utils/koishi");
84
84
  var import_logger7 = require("koishi-plugin-chatluna/utils/logger");
85
85
  var request = __toESM(require("koishi-plugin-chatluna/utils/request"), 1);
86
86
 
@@ -784,7 +784,6 @@ var import_error = require("koishi-plugin-chatluna/utils/error");
784
784
  var import_tool2 = require("@langchain/core/messages/tool");
785
785
  var import_koishi_plugin_chatluna = require("koishi-plugin-chatluna");
786
786
  var import_langchain = require("koishi-plugin-chatluna/utils/langchain");
787
- var import_zod = require("zod");
788
787
 
789
788
  // src/llm-core/chain/infinite_context_chain.ts
790
789
  var import_prompts = require("@langchain/core/prompts");
@@ -837,7 +836,7 @@ __name(formatAgentTaskWakeup, "formatAgentTaskWakeup");
837
836
  // src/llm-core/agent/sub-agent/tool.ts
838
837
  var import_messages3 = require("@langchain/core/messages");
839
838
  var import_tools2 = require("@langchain/core/tools");
840
- var import_zod2 = require("zod");
839
+ var import_zod = require("zod");
841
840
 
842
841
  // src/llm-core/agent/wakeup.ts
843
842
  function applyAgentTaskWakeup(ctx, config) {
@@ -2978,41 +2977,54 @@ function apply12(ctx, config, chain) {
2978
2977
  __name(apply12, "apply");
2979
2978
 
2980
2979
  // src/middlewares/chat/censor.ts
2981
- var import_string6 = require("koishi-plugin-chatluna/utils/string");
2980
+ var import_koishi6 = require("koishi");
2981
+ var import_langchain2 = require("koishi-plugin-chatluna/utils/langchain");
2982
2982
  function apply13(ctx, config, chain) {
2983
2983
  chain.middleware("censor", async (session, context) => {
2984
2984
  const message = context.options.responseMessage;
2985
2985
  if (!config.censor || message == null) {
2986
2986
  return 0 /* SKIPPED */;
2987
2987
  }
2988
- const baseContent = message.content;
2989
- if (typeof baseContent === "string") {
2990
- message.content = await ctx.censor.transform(
2991
- baseContent,
2992
- session
2993
- );
2994
- return 2 /* CONTINUE */;
2995
- }
2996
- message.content = await Promise.all(
2997
- baseContent.map((content) => {
2998
- if (!(0, import_string6.isMessageContentText)(content)) {
2999
- return content;
3000
- }
3001
- return {
3002
- type: "text",
3003
- text: ctx.censor.transform(content.text, session)
3004
- };
3005
- })
3006
- );
2988
+ message.content = (await censorMessage(
2989
+ ctx,
2990
+ message,
2991
+ context.options.deliverySession ?? session
2992
+ )).content;
2993
+ return 2 /* CONTINUE */;
3007
2994
  }).before("lifecycle-send").after("lifecycle-request_conversation");
3008
2995
  }
3009
2996
  __name(apply13, "apply");
2997
+ async function censorMessage(ctx, msg, session) {
2998
+ if (typeof msg.content === "string") {
2999
+ const text = await ctx.censor.transform([import_koishi6.h.text(msg.content)], session);
3000
+ return { ...msg, content: import_koishi6.h.unescape(text.join("")) };
3001
+ }
3002
+ const parts = [];
3003
+ for (const el of msg.content) {
3004
+ const prev = parts[parts.length - 1];
3005
+ if (prev && (0, import_langchain2.isMessageContentText)(prev) && (0, import_langchain2.isMessageContentText)(el)) {
3006
+ prev.text += el.text;
3007
+ continue;
3008
+ }
3009
+ parts.push((0, import_langchain2.isMessageContentText)(el) ? { ...el } : el);
3010
+ }
3011
+ const content = await Promise.all(
3012
+ parts.map(async (el) => {
3013
+ if (!(0, import_langchain2.isMessageContentText)(el)) return el;
3014
+ const text = await ctx.censor.transform([import_koishi6.h.text(el.text)], session);
3015
+ el.text = import_koishi6.h.unescape(text.join(""));
3016
+ return el;
3017
+ })
3018
+ );
3019
+ return { ...msg, content };
3020
+ }
3021
+ __name(censorMessage, "censorMessage");
3010
3022
 
3011
3023
  // src/middlewares/chat/chat_time_limit_check.ts
3012
3024
  var import_count_tokens2 = require("koishi-plugin-chatluna/llm-core/utils/count_tokens");
3013
3025
 
3014
3026
  // src/cache.ts
3015
- var import_koishi6 = require("koishi");
3027
+ var import_koishi7 = require("koishi");
3016
3028
  var Cache = class {
3017
3029
  constructor(ctx, config, tableName) {
3018
3030
  this.config = config;
@@ -3072,7 +3084,7 @@ var DatabaseCache = class {
3072
3084
  );
3073
3085
  ctx.setInterval(async () => {
3074
3086
  await ctx.database.remove("cache", { expire: { $lt: /* @__PURE__ */ new Date() } });
3075
- }, 10 * import_koishi6.Time.minute);
3087
+ }, 10 * import_koishi7.Time.minute);
3076
3088
  }
3077
3089
  ctx;
3078
3090
  static {
@@ -3527,10 +3539,10 @@ function createPendingMessage(session, conversation, inputMessage) {
3527
3539
  __name(createPendingMessage, "createPendingMessage");
3528
3540
 
3529
3541
  // src/middlewares/chat/read_chat_message.ts
3530
- var import_koishi7 = require("koishi");
3531
- var import_string7 = require("koishi-plugin-chatluna/utils/string");
3542
+ var import_koishi8 = require("koishi");
3543
+ var import_string6 = require("koishi-plugin-chatluna/utils/string");
3532
3544
  var import_types5 = require("koishi-plugin-chatluna/llm-core/platform/types");
3533
- var import_koishi8 = require("koishi-plugin-chatluna/utils/koishi");
3545
+ var import_koishi9 = require("koishi-plugin-chatluna/utils/koishi");
3534
3546
  var import_count_tokens3 = require("koishi-plugin-chatluna/llm-core/utils/count_tokens");
3535
3547
  var import_base64 = require("koishi-plugin-chatluna/utils/base64");
3536
3548
 
@@ -3577,10 +3589,10 @@ function apply18(ctx, config, chain) {
3577
3589
  chain.middleware("read_chat_message", async (session, context) => {
3578
3590
  let message = context.command != null ? context.message : session.elements;
3579
3591
  if (typeof message === "string") {
3580
- message = [import_koishi7.h.text(message)];
3592
+ message = [import_koishi8.h.text(message)];
3581
3593
  }
3582
3594
  if (context.command == null) {
3583
- const text = import_koishi7.h.select(message, "text").join("");
3595
+ const text = import_koishi8.h.select(message, "text").join("");
3584
3596
  const parsed = parsePresetLaneInput(
3585
3597
  text,
3586
3598
  ctx.chatluna.preset.getKeywordTriggerAliases().value
@@ -3616,7 +3628,7 @@ function apply18(ctx, config, chain) {
3616
3628
  continue;
3617
3629
  }
3618
3630
  next.push(
3619
- (0, import_koishi7.h)("text", {
3631
+ (0, import_koishi8.h)("text", {
3620
3632
  ...element.attrs,
3621
3633
  content: content.slice(skip)
3622
3634
  })
@@ -3667,7 +3679,7 @@ function apply18(ctx, config, chain) {
3667
3679
  );
3668
3680
  }
3669
3681
  }
3670
- if (transformedMessage.content.length < 1 && (0, import_string7.getMessageContent)(transformedMessage.content).trim().length < 1) {
3682
+ if (transformedMessage.content.length < 1 && (0, import_string6.getMessageContent)(transformedMessage.content).trim().length < 1) {
3671
3683
  return 1 /* STOP */;
3672
3684
  }
3673
3685
  context.options.inputMessage = transformedMessage;
@@ -3706,7 +3718,7 @@ function apply18(ctx, config, chain) {
3706
3718
  "message",
3707
3719
  async (session, element, message) => {
3708
3720
  if (!config.attachForwardMsgIdToContext) return;
3709
- if (!(0, import_koishi8.isForwardMessageElement)(element)) return;
3721
+ if (!(0, import_koishi9.isForwardMessageElement)(element)) return;
3710
3722
  trackForwardId(forwardHistory, element, message);
3711
3723
  }
3712
3724
  );
@@ -3733,7 +3745,7 @@ function apply18(ctx, config, chain) {
3733
3745
  }
3734
3746
  }
3735
3747
  const url = element.attrs.url ?? element.attrs.src;
3736
- const hash = await (0, import_string7.hashString)(url, 8);
3748
+ const hash = await (0, import_string6.hashString)(url, 8);
3737
3749
  element.attrs["imageHash"] = hash;
3738
3750
  const displayUrl = url.length > 100 ? url.substring(0, 100) + "..." : url;
3739
3751
  logger10.debug(`Processing image: ${displayUrl}`);
@@ -3933,7 +3945,7 @@ async function handleFileElement(ctx, fileSizes, session, element, message, mode
3933
3945
  logger10.error(`Failed to read file from ${sourceUrl}:`, error);
3934
3946
  return false;
3935
3947
  }
3936
- const mimeType = responseMimeType ?? (0, import_string7.getMimeTypeFromSource)(sourceUrl, name2);
3948
+ const mimeType = responseMimeType ?? (0, import_string6.getMimeTypeFromSource)(sourceUrl, name2);
3937
3949
  const fileName = name2 ?? "attachment";
3938
3950
  let label;
3939
3951
  switch (elementType) {
@@ -4007,7 +4019,7 @@ __name(handleFileElement, "handleFileElement");
4007
4019
  async function readImage(ctx, url) {
4008
4020
  if (url.startsWith("data:image") && url.includes("base64")) {
4009
4021
  const buffer = Buffer.from(url.split(",")[1], "base64");
4010
- const ext = (0, import_string7.getImageType)(buffer);
4022
+ const ext = (0, import_string6.getImageType)(buffer);
4011
4023
  return {
4012
4024
  base64Source: url,
4013
4025
  buffer,
@@ -4022,7 +4034,7 @@ async function readImage(ctx, url) {
4022
4034
  });
4023
4035
  const buffer = Buffer.from(response.data);
4024
4036
  const base64 = buffer.toString("base64");
4025
- const ext = (0, import_string7.getImageType)(buffer);
4037
+ const ext = (0, import_string6.getImageType)(buffer);
4026
4038
  return {
4027
4039
  base64Source: `data:${ext};base64,${base64}`,
4028
4040
  buffer,
@@ -4114,7 +4126,7 @@ function trackForwardId(history, element, message) {
4114
4126
  };
4115
4127
  history.set(message, state);
4116
4128
  state.hasForwardHistory = true;
4117
- const id = (0, import_koishi8.pickForwardMessageId)(element);
4129
+ const id = (0, import_koishi9.pickForwardMessageId)(element);
4118
4130
  if (id && !state.ids.includes(id)) {
4119
4131
  state.ids.push(id);
4120
4132
  }
@@ -4140,13 +4152,13 @@ function appendQQAttachments(session, elements) {
4140
4152
  }
4141
4153
  if (type === "file") {
4142
4154
  elements.push(
4143
- import_koishi7.h.file(src, {
4155
+ import_koishi8.h.file(src, {
4144
4156
  filename: attachment.filename
4145
4157
  })
4146
4158
  );
4147
4159
  } else if (type.startsWith("audio/")) {
4148
4160
  elements.push(
4149
- import_koishi7.h.audio(src, {
4161
+ import_koishi8.h.audio(src, {
4150
4162
  filename: attachment.filename,
4151
4163
  type,
4152
4164
  chatluna_file_url: src
@@ -4154,7 +4166,7 @@ function appendQQAttachments(session, elements) {
4154
4166
  );
4155
4167
  } else if (type === "voice") {
4156
4168
  elements.push(
4157
- import_koishi7.h.audio(src, {
4169
+ import_koishi8.h.audio(src, {
4158
4170
  filename: attachment.filename,
4159
4171
  type,
4160
4172
  chatluna_file_url: src
@@ -4162,7 +4174,7 @@ function appendQQAttachments(session, elements) {
4162
4174
  );
4163
4175
  } else if (type.startsWith("video/")) {
4164
4176
  elements.push(
4165
- import_koishi7.h.video(src, {
4177
+ import_koishi8.h.video(src, {
4166
4178
  filename: attachment.filename,
4167
4179
  width: attachment.width,
4168
4180
  height: attachment.height,
@@ -4203,8 +4215,8 @@ async function renderMessage(ctx, message, options) {
4203
4215
  __name(renderMessage, "renderMessage");
4204
4216
 
4205
4217
  // src/middlewares/chat/rollback_chat.ts
4206
- var import_string8 = require("koishi-plugin-chatluna/utils/string");
4207
- var import_koishi9 = require("koishi-plugin-chatluna/utils/koishi");
4218
+ var import_string7 = require("koishi-plugin-chatluna/utils/string");
4219
+ var import_koishi10 = require("koishi-plugin-chatluna/utils/koishi");
4208
4220
  var MAX_ROLLBACK_HOPS = 1e3;
4209
4221
  function apply20(ctx, config, chain) {
4210
4222
  chain.middleware("rollback_chat", async (session, context) => {
@@ -4258,7 +4270,7 @@ __name(apply20, "apply");
4258
4270
  async function decodeMessageContent(message) {
4259
4271
  try {
4260
4272
  if (message.content != null) {
4261
- return JSON.parse(await (0, import_string8.gzipDecode)(message.content));
4273
+ return JSON.parse(await (0, import_string7.gzipDecode)(message.content));
4262
4274
  }
4263
4275
  return message.text ?? "";
4264
4276
  } catch {
@@ -4276,7 +4288,7 @@ async function rollbackConversation(ctx, config, session, context, conversation,
4276
4288
  msg: session.text(".conversation_not_exist")
4277
4289
  };
4278
4290
  }
4279
- if (resolved.constraint.manageMode === "admin" && !await (0, import_koishi9.checkAdmin)(session)) {
4291
+ if (resolved.constraint.manageMode === "admin" && !await (0, import_koishi10.checkAdmin)(session)) {
4280
4292
  return {
4281
4293
  status: 1 /* STOP */,
4282
4294
  msg: session.text(".conversation_not_exist")
@@ -4342,7 +4354,7 @@ async function rollbackConversation(ctx, config, session, context, conversation,
4342
4354
  const humanContent = await decodeMessageContent(humanMessage);
4343
4355
  inputMessage = await ctx.chatluna.messageTransformer.transform(
4344
4356
  session,
4345
- (0, import_koishi9.transformMessageContentToElements)(humanContent),
4357
+ (0, import_koishi10.transformMessageContentToElements)(humanContent),
4346
4358
  ctx.chatluna.conversation.pickModel(resolved.constraint, current) ?? current.model,
4347
4359
  {
4348
4360
  content: "",
@@ -4374,7 +4386,7 @@ async function rollbackConversation(ctx, config, session, context, conversation,
4374
4386
  __name(rollbackConversation, "rollbackConversation");
4375
4387
 
4376
4388
  // src/middlewares/chat/stop_chat.ts
4377
- var import_koishi10 = require("koishi-plugin-chatluna/utils/koishi");
4389
+ var import_koishi11 = require("koishi-plugin-chatluna/utils/koishi");
4378
4390
  function apply21(ctx, config, chain) {
4379
4391
  chain.middleware("stop_chat", async (session, context) => {
4380
4392
  const { command: command2 } = context;
@@ -4396,7 +4408,7 @@ function apply21(ctx, config, chain) {
4396
4408
  context.message = session.text(".no_active_chat");
4397
4409
  return 1 /* STOP */;
4398
4410
  }
4399
- if (resolved.constraint.manageMode === "admin" && !await (0, import_koishi10.checkAdmin)(session)) {
4411
+ if (resolved.constraint.manageMode === "admin" && !await (0, import_koishi11.checkAdmin)(session)) {
4400
4412
  context.message = session.text(".stop_failed");
4401
4413
  return 1 /* STOP */;
4402
4414
  }
@@ -4487,7 +4499,7 @@ __name(apply23, "apply");
4487
4499
  var import_error6 = require("koishi-plugin-chatluna/utils/error");
4488
4500
  var import_logger4 = require("koishi-plugin-chatluna/utils/logger");
4489
4501
  var import_chains = require("koishi-plugin-chatluna/chains");
4490
- var import_string9 = require("koishi-plugin-chatluna/utils/string");
4502
+ var import_string8 = require("koishi-plugin-chatluna/utils/string");
4491
4503
  var logger12;
4492
4504
  function apply24(ctx, config, chain) {
4493
4505
  logger12 = (0, import_logger4.createLogger)(ctx);
@@ -4522,7 +4534,7 @@ function apply24(ctx, config, chain) {
4522
4534
  conversation
4523
4535
  );
4524
4536
  }
4525
- const postHandler = presetTemplate.config?.postHandler ? new import_string9.PresetPostHandler(
4537
+ const postHandler = presetTemplate.config?.postHandler ? new import_string8.PresetPostHandler(
4526
4538
  ctx,
4527
4539
  config,
4528
4540
  presetTemplate.config?.postHandler
@@ -4535,6 +4547,7 @@ function apply24(ctx, config, chain) {
4535
4547
  {
4536
4548
  enabled: config.streamResponse && shouldSend && context.options.deliverySession == null,
4537
4549
  send: shouldSend && !captureOnly,
4550
+ censor: postHandler?.censor,
4538
4551
  renderOptions: {
4539
4552
  ...context.options.renderOptions,
4540
4553
  session: deliverySession,
@@ -4556,8 +4569,8 @@ function apply24(ctx, config, chain) {
4556
4569
  ),
4557
4570
  stream: config.streamResponse && shouldSend,
4558
4571
  variables: {
4559
- prompt: (0, import_string9.getMessageContent)(originContent),
4560
- ...(0, import_string9.getSystemPromptVariables)(
4572
+ prompt: (0, import_string8.getMessageContent)(originContent),
4573
+ ...(0, import_string8.getSystemPromptVariables)(
4561
4574
  session,
4562
4575
  config,
4563
4576
  conversation
@@ -4590,7 +4603,7 @@ function apply24(ctx, config, chain) {
4590
4603
  });
4591
4604
  return import_chains.ChainMiddlewareRunStatus.CONTINUE;
4592
4605
  } catch (e) {
4593
- const err = e?.message?.includes("output values have 1 keys") ? new import_error6.ChatLunaError(
4606
+ const err = e instanceof Error && e.message.includes("output values have 1 keys") ? new import_error6.ChatLunaError(
4594
4607
  import_error6.ChatLunaErrorCode.MODEL_RESPONSE_IS_EMPTY
4595
4608
  ) : e;
4596
4609
  if (replyStream != null) {
@@ -4644,7 +4657,7 @@ function createChatCallbacks(context, config, stream, captureOnly) {
4644
4657
  await stream.write({
4645
4658
  type: "mark",
4646
4659
  name: "tool",
4647
- content: (0, import_string9.formatToolCall)(context.session, tool),
4660
+ content: (0, import_string8.formatToolCall)(context.session, tool),
4648
4661
  instant: true
4649
4662
  });
4650
4663
  }
@@ -4653,7 +4666,7 @@ function createChatCallbacks(context, config, stream, captureOnly) {
4653
4666
  __name(createChatCallbacks, "createChatCallbacks");
4654
4667
  async function processUserPrompt(config, presetTemplate, session, originContent, conversation) {
4655
4668
  if (typeof originContent === "string") {
4656
- return (await (0, import_string9.formatUserPromptString)(
4669
+ return (await (0, import_string8.formatUserPromptString)(
4657
4670
  config,
4658
4671
  presetTemplate,
4659
4672
  session,
@@ -4664,7 +4677,7 @@ async function processUserPrompt(config, presetTemplate, session, originContent,
4664
4677
  return Promise.all(
4665
4678
  originContent.map(async (message) => {
4666
4679
  if (message.type !== "text") return message;
4667
- const text = (await (0, import_string9.formatUserPromptString)(
4680
+ const text = (await (0, import_string8.formatUserPromptString)(
4668
4681
  config,
4669
4682
  presetTemplate,
4670
4683
  session,
@@ -5575,10 +5588,10 @@ function apply39(ctx, config, chain) {
5575
5588
  __name(apply39, "apply");
5576
5589
 
5577
5590
  // src/middlewares/system/conversation_manage.ts
5578
- var import_koishi11 = require("koishi");
5591
+ var import_koishi12 = require("koishi");
5579
5592
  var import_error8 = require("koishi-plugin-chatluna/utils/error");
5580
5593
  var import_pagination7 = require("koishi-plugin-chatluna/utils/pagination");
5581
- var import_koishi12 = require("koishi-plugin-chatluna/utils/koishi");
5594
+ var import_koishi13 = require("koishi-plugin-chatluna/utils/koishi");
5582
5595
  var import_promises6 = __toESM(require("fs/promises"), 1);
5583
5596
  function apply40(ctx, config, chain) {
5584
5597
  function middleware2(name2, fn) {
@@ -5601,7 +5614,7 @@ function apply40(ctx, config, chain) {
5601
5614
  );
5602
5615
  return 1 /* STOP */;
5603
5616
  }
5604
- if (resolved.constraint.manageMode === "admin" && resolved.constraint.routeMode !== "personal" && !await (0, import_koishi12.checkAdmin)(session)) {
5617
+ if (resolved.constraint.manageMode === "admin" && resolved.constraint.routeMode !== "personal" && !await (0, import_koishi13.checkAdmin)(session)) {
5605
5618
  context.message = session.text(
5606
5619
  "chatluna.conversation.messages.admin_required",
5607
5620
  [import_error8.ChatLunaErrorCode.CONVERSATION_ADMIN_REQUIRED]
@@ -5944,7 +5957,7 @@ function apply40(ctx, config, chain) {
5944
5957
  try {
5945
5958
  const buffer = await import_promises6.default.readFile(result.path);
5946
5959
  await session.send(
5947
- import_koishi11.h.file(buffer, "application/markdown", {
5960
+ import_koishi12.h.file(buffer, "application/markdown", {
5948
5961
  title: result.conversation.title + ".md"
5949
5962
  })
5950
5963
  );
@@ -6706,106 +6719,106 @@ async function unbindConversation(ctx, conversationId) {
6706
6719
  __name(unbindConversation, "unbindConversation");
6707
6720
 
6708
6721
  // src/config.ts
6709
- var import_koishi13 = require("koishi");
6710
- var Config2 = import_koishi13.Schema.intersect([
6711
- import_koishi13.Schema.object({
6712
- botNames: import_koishi13.Schema.array(import_koishi13.Schema.string()).default(["香草"]),
6713
- isNickname: import_koishi13.Schema.boolean().default(true),
6714
- isNickNameWithContent: import_koishi13.Schema.boolean().default(false)
6722
+ var import_koishi14 = require("koishi");
6723
+ var Config2 = import_koishi14.Schema.intersect([
6724
+ import_koishi14.Schema.object({
6725
+ botNames: import_koishi14.Schema.array(import_koishi14.Schema.string()).default(["香草"]),
6726
+ isNickname: import_koishi14.Schema.boolean().default(true),
6727
+ isNickNameWithContent: import_koishi14.Schema.boolean().default(false)
6715
6728
  }),
6716
- import_koishi13.Schema.object({
6717
- allowPrivate: import_koishi13.Schema.boolean().default(true),
6718
- allowAtReply: import_koishi13.Schema.boolean().default(true),
6719
- allowQuoteReply: import_koishi13.Schema.boolean().default(false),
6720
- privateChatWithoutCommand: import_koishi13.Schema.boolean().default(true),
6721
- includeQuoteReply: import_koishi13.Schema.boolean().default(true),
6722
- randomReplyFrequency: import_koishi13.Schema.percent().min(0).max(1).step(0.01).default(0).computed(),
6723
- attachForwardMsgIdToContext: import_koishi13.Schema.boolean().default(false),
6724
- autoUpdateConversationModel: import_koishi13.Schema.boolean().default(false)
6729
+ import_koishi14.Schema.object({
6730
+ allowPrivate: import_koishi14.Schema.boolean().default(true),
6731
+ allowAtReply: import_koishi14.Schema.boolean().default(true),
6732
+ allowQuoteReply: import_koishi14.Schema.boolean().default(false),
6733
+ privateChatWithoutCommand: import_koishi14.Schema.boolean().default(true),
6734
+ includeQuoteReply: import_koishi14.Schema.boolean().default(true),
6735
+ randomReplyFrequency: import_koishi14.Schema.percent().min(0).max(1).step(0.01).default(0).computed(),
6736
+ attachForwardMsgIdToContext: import_koishi14.Schema.boolean().default(false),
6737
+ autoUpdateConversationModel: import_koishi14.Schema.boolean().default(false)
6725
6738
  }),
6726
- import_koishi13.Schema.intersect([
6727
- import_koishi13.Schema.object({
6728
- isForwardMsg: import_koishi13.Schema.boolean().default(false)
6739
+ import_koishi14.Schema.intersect([
6740
+ import_koishi14.Schema.object({
6741
+ isForwardMsg: import_koishi14.Schema.boolean().default(false)
6729
6742
  }),
6730
- import_koishi13.Schema.union([
6731
- import_koishi13.Schema.object({
6732
- isForwardMsg: import_koishi13.Schema.const(true).required(),
6733
- forwardMsgMinLength: import_koishi13.Schema.number().min(0).max(400).step(1).default(0)
6743
+ import_koishi14.Schema.union([
6744
+ import_koishi14.Schema.object({
6745
+ isForwardMsg: import_koishi14.Schema.const(true).required(),
6746
+ forwardMsgMinLength: import_koishi14.Schema.number().min(0).max(400).step(1).default(0)
6734
6747
  }),
6735
- import_koishi13.Schema.object({})
6748
+ import_koishi14.Schema.object({})
6736
6749
  ])
6737
6750
  ]),
6738
- import_koishi13.Schema.intersect([
6739
- import_koishi13.Schema.object({
6740
- isReplyWithAt: import_koishi13.Schema.boolean().default(false)
6751
+ import_koishi14.Schema.intersect([
6752
+ import_koishi14.Schema.object({
6753
+ isReplyWithAt: import_koishi14.Schema.boolean().default(false)
6741
6754
  }),
6742
- import_koishi13.Schema.union([
6743
- import_koishi13.Schema.object({
6744
- isReplyWithAt: import_koishi13.Schema.const(true).required(),
6745
- replyQuoteThreshold: import_koishi13.Schema.number().min(0).max(600).step(1).default(0)
6755
+ import_koishi14.Schema.union([
6756
+ import_koishi14.Schema.object({
6757
+ isReplyWithAt: import_koishi14.Schema.const(true).required(),
6758
+ replyQuoteThreshold: import_koishi14.Schema.number().min(0).max(600).step(1).default(0)
6746
6759
  }),
6747
- import_koishi13.Schema.object({})
6760
+ import_koishi14.Schema.object({})
6748
6761
  ])
6749
6762
  ]),
6750
- import_koishi13.Schema.object({
6751
- sendThinkingMessage: import_koishi13.Schema.boolean().default(true),
6752
- sendThinkingMessageTimeout: import_koishi13.Schema.number().default(15e3),
6753
- msgCooldown: import_koishi13.Schema.number().min(0).max(3600).step(1).default(0),
6754
- messageQueue: import_koishi13.Schema.boolean().default(true),
6755
- messageQueueDelay: import_koishi13.Schema.number().min(0).max(60 * 30).default(0),
6756
- agentTaskAutoWakeup: import_koishi13.Schema.boolean().default(true),
6757
- showThoughtMessage: import_koishi13.Schema.boolean().default(false)
6763
+ import_koishi14.Schema.object({
6764
+ sendThinkingMessage: import_koishi14.Schema.boolean().default(true),
6765
+ sendThinkingMessageTimeout: import_koishi14.Schema.number().default(15e3),
6766
+ msgCooldown: import_koishi14.Schema.number().min(0).max(3600).step(1).default(0),
6767
+ messageQueue: import_koishi14.Schema.boolean().default(true),
6768
+ messageQueueDelay: import_koishi14.Schema.number().min(0).max(60 * 30).default(0),
6769
+ agentTaskAutoWakeup: import_koishi14.Schema.boolean().default(true),
6770
+ showThoughtMessage: import_koishi14.Schema.boolean().default(false)
6758
6771
  }),
6759
- import_koishi13.Schema.object({
6760
- outputMode: import_koishi13.Schema.dynamic("output-mode").default("text"),
6761
- splitMessage: import_koishi13.Schema.union([
6762
- import_koishi13.Schema.const("none"),
6763
- import_koishi13.Schema.const("punctuation"),
6764
- import_koishi13.Schema.const("paragraph")
6772
+ import_koishi14.Schema.object({
6773
+ outputMode: import_koishi14.Schema.dynamic("output-mode").default("text"),
6774
+ splitMessage: import_koishi14.Schema.union([
6775
+ import_koishi14.Schema.const("none"),
6776
+ import_koishi14.Schema.const("punctuation"),
6777
+ import_koishi14.Schema.const("paragraph")
6765
6778
  ]).default("none"),
6766
- censor: import_koishi13.Schema.boolean().default(false),
6767
- rawOnCensor: import_koishi13.Schema.boolean().default(false),
6768
- streamResponse: import_koishi13.Schema.boolean().default(false)
6779
+ censor: import_koishi14.Schema.boolean().default(false),
6780
+ rawOnCensor: import_koishi14.Schema.boolean().default(false),
6781
+ streamResponse: import_koishi14.Schema.boolean().default(false)
6769
6782
  }),
6770
- import_koishi13.Schema.object({
6771
- blackList: import_koishi13.Schema.number().min(0).max(1).step(1).default(0).computed().default(0)
6783
+ import_koishi14.Schema.object({
6784
+ blackList: import_koishi14.Schema.number().min(0).max(1).step(1).default(0).computed().default(0)
6772
6785
  }),
6773
- import_koishi13.Schema.object({
6774
- infiniteContext: import_koishi13.Schema.boolean().default(true),
6775
- infiniteContextThreshold: import_koishi13.Schema.percent().min(0.5).max(0.95).step(0.01).default(0.85),
6776
- autoArchive: import_koishi13.Schema.boolean().default(false),
6777
- autoArchiveTimeout: import_koishi13.Schema.number().default(import_koishi13.Time.day * 10 / import_koishi13.Time.second).min(import_koishi13.Time.hour / import_koishi13.Time.second),
6778
- autoPurgeArchive: import_koishi13.Schema.boolean().default(false),
6779
- autoPurgeArchiveTimeout: import_koishi13.Schema.number().default(import_koishi13.Time.day * 30 / import_koishi13.Time.second).min(import_koishi13.Time.hour / import_koishi13.Time.second)
6786
+ import_koishi14.Schema.object({
6787
+ infiniteContext: import_koishi14.Schema.boolean().default(true),
6788
+ infiniteContextThreshold: import_koishi14.Schema.percent().min(0.5).max(0.95).step(0.01).default(0.85),
6789
+ autoArchive: import_koishi14.Schema.boolean().default(false),
6790
+ autoArchiveTimeout: import_koishi14.Schema.number().default(import_koishi14.Time.day * 10 / import_koishi14.Time.second).min(import_koishi14.Time.hour / import_koishi14.Time.second),
6791
+ autoPurgeArchive: import_koishi14.Schema.boolean().default(false),
6792
+ autoPurgeArchiveTimeout: import_koishi14.Schema.number().default(import_koishi14.Time.day * 30 / import_koishi14.Time.second).min(import_koishi14.Time.hour / import_koishi14.Time.second)
6780
6793
  }),
6781
- import_koishi13.Schema.object({
6782
- defaultEmbeddings: import_koishi13.Schema.dynamic("embeddings").default("无"),
6783
- defaultVectorStore: import_koishi13.Schema.dynamic("vector-store").default("无")
6794
+ import_koishi14.Schema.object({
6795
+ defaultEmbeddings: import_koishi14.Schema.dynamic("embeddings").default("无"),
6796
+ defaultVectorStore: import_koishi14.Schema.dynamic("vector-store").default("无")
6784
6797
  }),
6785
- import_koishi13.Schema.object({
6786
- defaultGroupRouteMode: import_koishi13.Schema.union([
6787
- import_koishi13.Schema.const("shared"),
6788
- import_koishi13.Schema.const("personal")
6798
+ import_koishi14.Schema.object({
6799
+ defaultGroupRouteMode: import_koishi14.Schema.union([
6800
+ import_koishi14.Schema.const("shared"),
6801
+ import_koishi14.Schema.const("personal")
6789
6802
  ]).default("shared"),
6790
- defaultChatMode: import_koishi13.Schema.dynamic("chat-mode").default("plugin"),
6791
- defaultModel: import_koishi13.Schema.dynamic("model").default("无"),
6792
- defaultPreset: import_koishi13.Schema.dynamic("preset").default("sydney"),
6793
- enablePresetKeywordTrigger: import_koishi13.Schema.boolean().default(true)
6803
+ defaultChatMode: import_koishi14.Schema.dynamic("chat-mode").default("plugin"),
6804
+ defaultModel: import_koishi14.Schema.dynamic("model").default("无"),
6805
+ defaultPreset: import_koishi14.Schema.dynamic("preset").default("sydney"),
6806
+ enablePresetKeywordTrigger: import_koishi14.Schema.boolean().default(true)
6794
6807
  }),
6795
- import_koishi13.Schema.object({
6796
- voiceSpeakId: import_koishi13.Schema.number().default(0),
6797
- isLog: import_koishi13.Schema.boolean().default(false)
6808
+ import_koishi14.Schema.object({
6809
+ voiceSpeakId: import_koishi14.Schema.number().default(0),
6810
+ isLog: import_koishi14.Schema.boolean().default(false)
6798
6811
  }),
6799
- import_koishi13.Schema.intersect([
6800
- import_koishi13.Schema.object({
6801
- isProxy: import_koishi13.Schema.boolean().default(false)
6812
+ import_koishi14.Schema.intersect([
6813
+ import_koishi14.Schema.object({
6814
+ isProxy: import_koishi14.Schema.boolean().default(false)
6802
6815
  }),
6803
- import_koishi13.Schema.union([
6804
- import_koishi13.Schema.object({
6805
- isProxy: import_koishi13.Schema.const(true).required(),
6806
- proxyAddress: import_koishi13.Schema.string().default("http://127.0.0.1:7897")
6816
+ import_koishi14.Schema.union([
6817
+ import_koishi14.Schema.object({
6818
+ isProxy: import_koishi14.Schema.const(true).required(),
6819
+ proxyAddress: import_koishi14.Schema.string().default("http://127.0.0.1:7897")
6807
6820
  }),
6808
- import_koishi13.Schema.object({})
6821
+ import_koishi14.Schema.object({})
6809
6822
  ])
6810
6823
  ])
6811
6824
  ]).i18n({
@@ -6814,23 +6827,23 @@ var Config2 = import_koishi13.Schema.intersect([
6814
6827
  });
6815
6828
 
6816
6829
  // src/render/index.ts
6817
- var import_koishi25 = require("koishi");
6830
+ var import_koishi26 = require("koishi");
6818
6831
  var import_error9 = require("koishi-plugin-chatluna/utils/error");
6819
6832
 
6820
6833
  // src/render/koishi-element.ts
6821
- var import_koishi17 = require("koishi");
6834
+ var import_koishi18 = require("koishi");
6822
6835
  var import_koishi_plugin_chatluna9 = require("koishi-plugin-chatluna");
6823
- var import_string12 = require("koishi-plugin-chatluna/utils/string");
6824
- var import_koishi18 = require("koishi-plugin-chatluna/utils/koishi");
6836
+ var import_string11 = require("koishi-plugin-chatluna/utils/string");
6837
+ var import_koishi19 = require("koishi-plugin-chatluna/utils/koishi");
6825
6838
 
6826
6839
  // src/render/base.ts
6827
- var import_koishi16 = require("koishi");
6828
- var import_string11 = require("koishi-plugin-chatluna/utils/string");
6840
+ var import_koishi17 = require("koishi");
6841
+ var import_string10 = require("koishi-plugin-chatluna/utils/string");
6829
6842
 
6830
6843
  // src/render/split.ts
6831
- var import_koishi14 = require("koishi");
6832
- var import_string10 = require("koishi-plugin-chatluna/utils/string");
6833
- var import_koishi15 = require("koishi-plugin-chatluna/utils/koishi");
6844
+ var import_koishi15 = require("koishi");
6845
+ var import_string9 = require("koishi-plugin-chatluna/utils/string");
6846
+ var import_koishi16 = require("koishi-plugin-chatluna/utils/koishi");
6834
6847
 
6835
6848
  // src/render/sentence.ts
6836
6849
  var import_grapheme = require("unicode-segmenter/grapheme");
@@ -7032,7 +7045,7 @@ var TextStreamSplitter = class {
7032
7045
  inContent;
7033
7046
  stopped = false;
7034
7047
  write(chunk) {
7035
- return this.writeText((0, import_string10.getMessageContent)(chunk.content));
7048
+ return this.writeText((0, import_string9.getMessageContent)(chunk.content));
7036
7049
  }
7037
7050
  writeText(text) {
7038
7051
  if (!text || this.stopped) return [];
@@ -7105,21 +7118,21 @@ var MessageElementSplitter = class {
7105
7118
  }
7106
7119
  buf = "";
7107
7120
  write(chunk) {
7108
- return this.writeText((0, import_string10.getMessageContent)(chunk.content));
7121
+ return this.writeText((0, import_string9.getMessageContent)(chunk.content));
7109
7122
  }
7110
7123
  writeText(text) {
7111
7124
  if (!text) return [];
7112
7125
  this.buf += text;
7113
- const result = (0, import_koishi15.parseElements)(this.buf, true);
7126
+ const result = (0, import_koishi16.parseElements)(this.buf, true);
7114
7127
  this.buf = result.rest;
7115
7128
  return result.elements;
7116
7129
  }
7117
7130
  flush() {
7118
7131
  if (!this.buf.trim()) return [];
7119
7132
  try {
7120
- return (0, import_koishi15.parseElements)(this.buf);
7133
+ return (0, import_koishi16.parseElements)(this.buf);
7121
7134
  } catch {
7122
- return [import_koishi14.h.text(this.buf)];
7135
+ return [import_koishi15.h.text(this.buf)];
7123
7136
  } finally {
7124
7137
  this.buf = "";
7125
7138
  }
@@ -7181,7 +7194,7 @@ var BufferedRenderStreamSession = class {
7181
7194
  text = "";
7182
7195
  splitter;
7183
7196
  async write(chunk) {
7184
- return await this.writeText((0, import_string11.getMessageContent)(chunk.content));
7197
+ return await this.writeText((0, import_string10.getMessageContent)(chunk.content));
7185
7198
  }
7186
7199
  async flush() {
7187
7200
  if (this.plan.mode === "edit" && this.text.trim()) {
@@ -7214,7 +7227,7 @@ var BufferedRenderStreamSession = class {
7214
7227
  const elements = await this.renderText(part);
7215
7228
  result.push(
7216
7229
  ...this.options.split && this.options.split !== "none" ? elements.map(
7217
- (el) => el.type === "message" ? el : (0, import_koishi16.h)("message", el)
7230
+ (el) => el.type === "message" ? el : (0, import_koishi17.h)("message", el)
7218
7231
  ) : elements
7219
7232
  );
7220
7233
  }
@@ -7228,11 +7241,11 @@ var KoishiElementRenderer = class extends Renderer {
7228
7241
  __name(this, "KoishiElementRenderer");
7229
7242
  }
7230
7243
  async render(message, options) {
7231
- let transformed = (0, import_string12.transformMessageContentToElements)(message.content);
7244
+ let transformed = (0, import_string11.transformMessageContentToElements)(message.content);
7232
7245
  transformed = transformAndEscape(transformed);
7233
7246
  if (options.split && options.split !== "none") {
7234
7247
  transformed = transformed.map(
7235
- (element) => element.type === "message" ? element : (0, import_koishi17.h)("message", element)
7248
+ (element) => element.type === "message" ? element : (0, import_koishi18.h)("message", element)
7236
7249
  );
7237
7250
  }
7238
7251
  return {
@@ -7249,7 +7262,7 @@ var KoishiElementRenderer = class extends Renderer {
7249
7262
  createStreamSession(options, plan) {
7250
7263
  return new KoishiElementStreamSession(options, plan);
7251
7264
  }
7252
- schema = import_koishi17.Schema.const("koishi-element").i18n({
7265
+ schema = import_koishi18.Schema.const("koishi-element").i18n({
7253
7266
  "zh-CN": "将回复作为 koishi 消息元素进行渲染",
7254
7267
  "en-US": "Render as koishi message element template"
7255
7268
  });
@@ -7273,12 +7286,12 @@ var KoishiElementStreamSession = class {
7273
7286
  if (!text) return null;
7274
7287
  if (this.plan.mode === "edit") {
7275
7288
  this.text += text;
7276
- return transformAndEscape([import_koishi17.h.text(this.text + "●")]);
7289
+ return transformAndEscape([import_koishi18.h.text(this.text + "●")]);
7277
7290
  }
7278
7291
  let elements = this.splitter.writeText(text);
7279
7292
  if (this.options.split && this.options.split !== "none") {
7280
7293
  elements = elements.map(
7281
- (el) => el.type === "message" ? el : (0, import_koishi17.h)("message", el)
7294
+ (el) => el.type === "message" ? el : (0, import_koishi18.h)("message", el)
7282
7295
  );
7283
7296
  }
7284
7297
  return elements.length > 0 ? elements : null;
@@ -7286,12 +7299,12 @@ var KoishiElementStreamSession = class {
7286
7299
  flush() {
7287
7300
  if (this.plan.mode === "buffer") return null;
7288
7301
  if (this.plan.mode === "edit" && this.text.trim()) {
7289
- return transformAndEscape([import_koishi17.h.text(this.text)]);
7302
+ return transformAndEscape([import_koishi18.h.text(this.text)]);
7290
7303
  }
7291
7304
  let elements = this.splitter.flush();
7292
7305
  if (this.options.split && this.options.split !== "none") {
7293
7306
  elements = elements.map(
7294
- (el) => el.type === "message" ? el : (0, import_koishi17.h)("message", el)
7307
+ (el) => el.type === "message" ? el : (0, import_koishi18.h)("message", el)
7295
7308
  );
7296
7309
  }
7297
7310
  return elements.length > 0 ? elements : null;
@@ -7310,24 +7323,24 @@ function transformAndEscape(source) {
7310
7323
  return element;
7311
7324
  }
7312
7325
  try {
7313
- return (0, import_koishi18.parseElements)(element.attrs["content"]);
7326
+ return (0, import_koishi19.parseElements)(element.attrs["content"]);
7314
7327
  } catch (e) {
7315
7328
  import_koishi_plugin_chatluna9.logger.error(e);
7316
- return [import_koishi17.h.text(element.attrs["content"])];
7329
+ return [import_koishi18.h.text(element.attrs["content"])];
7317
7330
  }
7318
7331
  });
7319
7332
  }
7320
7333
  __name(transformAndEscape, "transformAndEscape");
7321
7334
 
7322
7335
  // src/render/mixed-voice.ts
7323
- var import_koishi21 = require("koishi");
7336
+ var import_koishi22 = require("koishi");
7324
7337
  var import_koishi_plugin_chatluna10 = require("koishi-plugin-chatluna");
7325
- var import_string14 = require("koishi-plugin-chatluna/utils/string");
7338
+ var import_string13 = require("koishi-plugin-chatluna/utils/string");
7326
7339
 
7327
7340
  // src/render/text.ts
7328
- var import_koishi19 = require("koishi");
7329
- var import_string13 = require("koishi-plugin-chatluna/utils/string");
7330
- var import_koishi20 = require("koishi-plugin-chatluna/utils/koishi");
7341
+ var import_koishi20 = require("koishi");
7342
+ var import_string12 = require("koishi-plugin-chatluna/utils/string");
7343
+ var import_koishi21 = require("koishi-plugin-chatluna/utils/koishi");
7331
7344
  var TextRenderer = class extends Renderer {
7332
7345
  static {
7333
7346
  __name(this, "TextRenderer");
@@ -7336,12 +7349,12 @@ var TextRenderer = class extends Renderer {
7336
7349
  if (options.session != null && options.session.platform === "qq" && options.session.isDirect) {
7337
7350
  return {
7338
7351
  element: [
7339
- import_koishi19.h.text((0, import_string13.getMessageContent)(message.content)),
7340
- ...import_koishi19.h.parse("<markdown-qq></markdown-qq>")
7352
+ import_koishi20.h.text((0, import_string12.getMessageContent)(message.content)),
7353
+ ...import_koishi20.h.parse("<markdown-qq></markdown-qq>")
7341
7354
  ]
7342
7355
  };
7343
7356
  }
7344
- let transformed = (0, import_string13.transformMessageContentToElements)(message.content);
7357
+ let transformed = (0, import_string12.transformMessageContentToElements)(message.content);
7345
7358
  transformed = transformAndEscape2(
7346
7359
  transformed,
7347
7360
  options.session?.platform ?? "sandbox"
@@ -7350,16 +7363,16 @@ var TextRenderer = class extends Renderer {
7350
7363
  const element = transformed.shift();
7351
7364
  const content = element.attrs["content"];
7352
7365
  if (content) {
7353
- transformed.unshift(import_koishi19.h.text(content));
7366
+ transformed.unshift(import_koishi20.h.text(content));
7354
7367
  } else {
7355
7368
  transformed.unshift(...element.children);
7356
7369
  }
7357
7370
  }
7358
7371
  if (options.split && options.split !== "none") {
7359
7372
  transformed = transformed.flatMap((element) => {
7360
- if (element.type !== "text") return (0, import_koishi19.h)("message", element);
7373
+ if (element.type !== "text") return (0, import_koishi20.h)("message", element);
7361
7374
  return splitText2(element.attrs["content"], options.split).map(
7362
- (text) => (0, import_koishi19.h)("message", import_koishi19.h.text(text))
7375
+ (text) => (0, import_koishi20.h)("message", import_koishi20.h.text(text))
7363
7376
  );
7364
7377
  });
7365
7378
  }
@@ -7377,7 +7390,7 @@ var TextRenderer = class extends Renderer {
7377
7390
  createStreamSession(options, plan) {
7378
7391
  return new TextStreamSession(options, plan);
7379
7392
  }
7380
- schema = import_koishi19.Schema.const("text").i18n({
7393
+ schema = import_koishi20.Schema.const("text").i18n({
7381
7394
  "zh-CN": "将回复作为 markdown 进行渲染",
7382
7395
  "en-US": "Render as markdown"
7383
7396
  });
@@ -7391,14 +7404,14 @@ var TextStreamSession = class extends BufferedRenderStreamSession {
7391
7404
  }
7392
7405
  renderText(text) {
7393
7406
  const transformed = transformAndEscape2(
7394
- (0, import_string13.transformMessageContentToElements)(text),
7407
+ (0, import_string12.transformMessageContentToElements)(text),
7395
7408
  this.options.session?.platform ?? "sandbox"
7396
7409
  );
7397
7410
  if (transformed[0]?.type === "p") {
7398
7411
  const element = transformed.shift();
7399
7412
  const content = element.attrs["content"];
7400
7413
  if (content) {
7401
- transformed.unshift(import_koishi19.h.text(content));
7414
+ transformed.unshift(import_koishi20.h.text(content));
7402
7415
  } else {
7403
7416
  transformed.unshift(...element.children);
7404
7417
  }
@@ -7409,7 +7422,7 @@ var TextStreamSession = class extends BufferedRenderStreamSession {
7409
7422
  function transformAndEscape2(source, platform = "sandbox") {
7410
7423
  return source.flatMap((element) => {
7411
7424
  if (element.type === "text") {
7412
- return (0, import_koishi20.transformToMarkdown)(element.attrs["content"], platform);
7425
+ return (0, import_koishi21.transformToMarkdown)(element.attrs["content"], platform);
7413
7426
  }
7414
7427
  return element;
7415
7428
  });
@@ -7423,7 +7436,7 @@ var MixedVoiceRenderer = class extends Renderer {
7423
7436
  }
7424
7437
  async render(message, options) {
7425
7438
  const elements = [];
7426
- const baseElements = (0, import_string14.transformMessageContentToElements)(message.content);
7439
+ const baseElements = (0, import_string13.transformMessageContentToElements)(message.content);
7427
7440
  const text = (await this.renderText(baseElements, options)).element;
7428
7441
  if (Array.isArray(text)) {
7429
7442
  elements.push(...text);
@@ -7453,7 +7466,7 @@ var MixedVoiceRenderer = class extends Renderer {
7453
7466
  async renderText(messages, options) {
7454
7467
  let transformed = transformAndEscape2(messages);
7455
7468
  if (options.split && options.split !== "none") {
7456
- transformed = transformed.map((element) => (0, import_koishi21.h)("message", element));
7469
+ transformed = transformed.map((element) => (0, import_koishi22.h)("message", element));
7457
7470
  }
7458
7471
  return {
7459
7472
  element: transformed
@@ -7487,7 +7500,7 @@ var MixedVoiceRenderer = class extends Renderer {
7487
7500
  )
7488
7501
  );
7489
7502
  }
7490
- schema = import_koishi21.Schema.const("mixed-voice").i18n({
7503
+ schema = import_koishi22.Schema.const("mixed-voice").i18n({
7491
7504
  "zh-CN": "同时输出语音和文本",
7492
7505
  "en-US": "Output both voice and text"
7493
7506
  });
@@ -7504,10 +7517,10 @@ var MixedVoiceStreamSession = class extends BufferedRenderStreamSession {
7504
7517
  async renderText(text) {
7505
7518
  const result = [];
7506
7519
  const elements = transformAndEscape2(
7507
- (0, import_string14.transformMessageContentToElements)(text)
7520
+ (0, import_string13.transformMessageContentToElements)(text)
7508
7521
  );
7509
7522
  if (this.options.split && this.options.split !== "none") {
7510
- result.push(...elements.map((el) => (0, import_koishi21.h)("message", el)));
7523
+ result.push(...elements.map((el) => (0, import_koishi22.h)("message", el)));
7511
7524
  } else {
7512
7525
  result.push(...elements);
7513
7526
  }
@@ -7517,9 +7530,9 @@ var MixedVoiceStreamSession = class extends BufferedRenderStreamSession {
7517
7530
  };
7518
7531
 
7519
7532
  // src/render/pure-text.ts
7520
- var import_koishi22 = require("koishi");
7533
+ var import_koishi23 = require("koishi");
7521
7534
  var import_koishi_plugin_markdown = require("koishi-plugin-markdown");
7522
- var import_string15 = require("koishi-plugin-chatluna/utils/string");
7535
+ var import_string14 = require("koishi-plugin-chatluna/utils/string");
7523
7536
  var import_he = __toESM(require("he"), 1);
7524
7537
 
7525
7538
  // src/utils/remove-markdown.ts
@@ -7604,14 +7617,14 @@ var PureTextRenderer = class extends Renderer {
7604
7617
  __name(this, "PureTextRenderer");
7605
7618
  }
7606
7619
  async render(message, options) {
7607
- const transformed = (0, import_string15.transformMessageContentToElements)(message.content);
7620
+ const transformed = (0, import_string14.transformMessageContentToElements)(message.content);
7608
7621
  if (options.split && options.split !== "none") {
7609
7622
  return {
7610
7623
  element: transformed.flatMap((element) => {
7611
- if (element.type !== "text") return (0, import_koishi22.h)("message", element);
7624
+ if (element.type !== "text") return (0, import_koishi23.h)("message", element);
7612
7625
  const content = element.attrs["content"];
7613
7626
  return splitText2(content, options.split).map(
7614
- (text) => (0, import_koishi22.h)("message", import_koishi22.h.text(stripMarkdown(text)))
7627
+ (text) => (0, import_koishi23.h)("message", import_koishi23.h.text(stripMarkdown(text)))
7615
7628
  );
7616
7629
  })
7617
7630
  };
@@ -7619,7 +7632,7 @@ var PureTextRenderer = class extends Renderer {
7619
7632
  return {
7620
7633
  element: transformed.map((element) => {
7621
7634
  if (element.type !== "text") return element;
7622
- return import_koishi22.h.text(stripMarkdown(element.attrs["content"]));
7635
+ return import_koishi23.h.text(stripMarkdown(element.attrs["content"]));
7623
7636
  })
7624
7637
  };
7625
7638
  }
@@ -7633,7 +7646,7 @@ var PureTextRenderer = class extends Renderer {
7633
7646
  createStreamSession(options, plan) {
7634
7647
  return new PureTextStreamSession(options, plan);
7635
7648
  }
7636
- schema = import_koishi22.Schema.const("pure-text").i18n({
7649
+ schema = import_koishi23.Schema.const("pure-text").i18n({
7637
7650
  "zh-CN": "将回复渲染为纯文本(去除 markdown 格式)",
7638
7651
  "en-US": "Render as pure text (remove markdown format)"
7639
7652
  });
@@ -7646,7 +7659,7 @@ var PureTextStreamSession = class extends BufferedRenderStreamSession {
7646
7659
  super(options, plan);
7647
7660
  }
7648
7661
  renderText(text) {
7649
- return [import_koishi22.h.text(stripMarkdown(text))];
7662
+ return [import_koishi23.h.text(stripMarkdown(text))];
7650
7663
  }
7651
7664
  };
7652
7665
  function stripMarkdown(source) {
@@ -7655,8 +7668,8 @@ function stripMarkdown(source) {
7655
7668
  __name(stripMarkdown, "stripMarkdown");
7656
7669
 
7657
7670
  // src/render/raw.ts
7658
- var import_koishi23 = require("koishi");
7659
- var import_string16 = require("koishi-plugin-chatluna/utils/string");
7671
+ var import_koishi24 = require("koishi");
7672
+ var import_string15 = require("koishi-plugin-chatluna/utils/string");
7660
7673
  var RawRenderer = class extends Renderer {
7661
7674
  static {
7662
7675
  __name(this, "RawRenderer");
@@ -7664,11 +7677,11 @@ var RawRenderer = class extends Renderer {
7664
7677
  async render(message, options) {
7665
7678
  if (typeof message.content === "string") {
7666
7679
  return {
7667
- element: import_koishi23.h.text(message.content)
7680
+ element: import_koishi24.h.text(message.content)
7668
7681
  };
7669
7682
  }
7670
7683
  return {
7671
- element: (0, import_string16.transformMessageContentToElements)(message.content)
7684
+ element: (0, import_string15.transformMessageContentToElements)(message.content)
7672
7685
  };
7673
7686
  }
7674
7687
  getStreamPlan(options) {
@@ -7681,7 +7694,7 @@ var RawRenderer = class extends Renderer {
7681
7694
  createStreamSession(options, plan) {
7682
7695
  return new RawStreamSession(options, plan);
7683
7696
  }
7684
- schema = import_koishi23.Schema.const("raw").i18n({
7697
+ schema = import_koishi24.Schema.const("raw").i18n({
7685
7698
  "zh-CN": "原始输出",
7686
7699
  "en-US": "Raw text"
7687
7700
  });
@@ -7694,7 +7707,7 @@ var RawStreamSession = class extends BufferedRenderStreamSession {
7694
7707
  super(options, plan);
7695
7708
  }
7696
7709
  renderText(text) {
7697
- return [import_koishi23.h.text(text)];
7710
+ return [import_koishi24.h.text(text)];
7698
7711
  }
7699
7712
  };
7700
7713
 
@@ -7704,15 +7717,15 @@ var logger16;
7704
7717
  var ReplyStream = class {
7705
7718
  constructor(ctx, config, context, renderer, opts) {
7706
7719
  this.ctx = ctx;
7707
- this.config = config;
7708
7720
  this.context = context;
7709
7721
  this.renderer = renderer;
7710
7722
  logger16 = (0, import_logger6.createLogger)(ctx);
7723
+ this.moderated = config.censor || opts.censor === true;
7711
7724
  const options = {
7712
7725
  ...opts.renderOptions,
7713
7726
  session: context.options.deliverySession ?? opts.renderOptions?.session ?? context.session
7714
7727
  };
7715
- const plan = opts.enabled ? renderer.getStreamPlan(options) : { mode: "buffer" };
7728
+ const plan = opts.enabled && !this.moderated ? renderer.getStreamPlan(options) : { mode: "buffer" };
7716
7729
  this.mode = plan.mode;
7717
7730
  this.stream = renderer.createStreamSession(options, plan);
7718
7731
  this.queue = new ReplyQueue(
@@ -7723,7 +7736,6 @@ var ReplyStream = class {
7723
7736
  this.renderAdditional = opts.renderAdditional;
7724
7737
  }
7725
7738
  ctx;
7726
- config;
7727
7739
  context;
7728
7740
  renderer;
7729
7741
  static {
@@ -7737,11 +7749,13 @@ var ReplyStream = class {
7737
7749
  send = true;
7738
7750
  sentAdditional = false;
7739
7751
  closed = false;
7752
+ moderated;
7753
+ pending = [];
7740
7754
  renderMessage;
7741
7755
  renderAdditional;
7742
7756
  async write(frame) {
7743
7757
  if (frame.type === "content") {
7744
- if (this.closed) return;
7758
+ if (this.closed || this.mode === "buffer") return;
7745
7759
  if (this.firstChunk) {
7746
7760
  this.firstChunk = false;
7747
7761
  await this.context.recallThinkingMessage?.();
@@ -7753,6 +7767,10 @@ var ReplyStream = class {
7753
7767
  return;
7754
7768
  }
7755
7769
  if (frame.type === "mark" && frame.instant) {
7770
+ if (this.moderated) {
7771
+ this.pending.push({ content: frame.content ?? frame.name });
7772
+ return;
7773
+ }
7756
7774
  await this.sendMessage(
7757
7775
  { content: frame.content ?? frame.name },
7758
7776
  "split"
@@ -7773,6 +7791,7 @@ var ReplyStream = class {
7773
7791
  if (frame != null) {
7774
7792
  await this.write(frame);
7775
7793
  }
7794
+ if (this.moderated && this.finalMessage == null) return;
7776
7795
  if (frame?.type === "done" && this.mode === "split" && !this.closed) {
7777
7796
  return;
7778
7797
  }
@@ -7788,6 +7807,10 @@ var ReplyStream = class {
7788
7807
  }
7789
7808
  this.closed = true;
7790
7809
  await this.context.recallThinkingMessage?.();
7810
+ for (const message of this.pending) {
7811
+ await this.sendMessage(message, "split");
7812
+ }
7813
+ this.pending = [];
7791
7814
  if (this.mode === "buffer") {
7792
7815
  if (this.finalMessage != null) {
7793
7816
  await this.sendMessage(this.finalMessage, "split");
@@ -7807,7 +7830,7 @@ var ReplyStream = class {
7807
7830
  await this.finish();
7808
7831
  }
7809
7832
  async sendMessage(message, mode) {
7810
- const messages = await this.renderMessage(message);
7833
+ const messages = await this.renderMessage(await this.censor(message));
7811
7834
  for (const msg of messages) {
7812
7835
  const elements = Array.isArray(msg.element) ? msg.element : [msg.element];
7813
7836
  await this.sendElements(elements, mode);
@@ -7817,24 +7840,37 @@ var ReplyStream = class {
7817
7840
  if (this.sentAdditional) return;
7818
7841
  if (this.finalMessage == null || this.renderAdditional == null) return;
7819
7842
  this.sentAdditional = true;
7820
- const messages = await this.renderAdditional(this.finalMessage);
7843
+ let message = this.finalMessage;
7844
+ if (this.moderated && message.additionalReplyMessages != null) {
7845
+ message = {
7846
+ ...message,
7847
+ additionalReplyMessages: await Promise.all(
7848
+ message.additionalReplyMessages.map(
7849
+ (msg) => this.censor(msg)
7850
+ )
7851
+ )
7852
+ };
7853
+ }
7854
+ const messages = await this.renderAdditional(message);
7821
7855
  for (const elements of messages) {
7822
7856
  await this.sendElements(elements, "split");
7823
7857
  }
7824
7858
  }
7825
7859
  async sendElements(elements, mode = this.mode) {
7826
7860
  if (!this.send) return;
7827
- const processed = await this.censor(elements);
7828
- if (processed.length < 1) return;
7861
+ if (elements.length < 1) return;
7829
7862
  if (mode === "edit") {
7830
- return await this.queue.edit(processed);
7863
+ return await this.queue.edit(elements);
7831
7864
  }
7832
- await this.context.send([processed]);
7865
+ await this.context.send([elements]);
7833
7866
  }
7834
- async censor(elements) {
7835
- if (!this.config.censor) return elements;
7836
- const session = this.context.options.deliverySession ?? this.context.session;
7837
- return await this.ctx.censor.transform(elements, session);
7867
+ async censor(message) {
7868
+ if (!this.moderated) return message;
7869
+ return await censorMessage(
7870
+ this.ctx,
7871
+ message,
7872
+ this.context.options.deliverySession ?? this.context.session
7873
+ );
7838
7874
  }
7839
7875
  async finish() {
7840
7876
  await this.sendAdditional();
@@ -7885,15 +7921,15 @@ var ReplyQueue = class {
7885
7921
  };
7886
7922
 
7887
7923
  // src/render/voice.ts
7888
- var import_koishi24 = require("koishi");
7924
+ var import_koishi25 = require("koishi");
7889
7925
  var import_koishi_plugin_chatluna11 = require("koishi-plugin-chatluna");
7890
- var import_string17 = require("koishi-plugin-chatluna/utils/string");
7926
+ var import_string16 = require("koishi-plugin-chatluna/utils/string");
7891
7927
  var VoiceRenderer = class extends Renderer {
7892
7928
  static {
7893
7929
  __name(this, "VoiceRenderer");
7894
7930
  }
7895
7931
  async render(message, options) {
7896
- const baseElements = (0, import_string17.transformMessageContentToElements)(message.content);
7932
+ const baseElements = (0, import_string16.transformMessageContentToElements)(message.content);
7897
7933
  const splitMessages = this._splitMessage(baseElements).flatMap((text) => splitText2(text.trim(), options.split ?? "none")).filter((text) => text.length > 0);
7898
7934
  import_koishi_plugin_chatluna11.logger?.debug(`splitMessages: ${JSON.stringify(splitMessages)}`);
7899
7935
  if (splitMessages.length === 0) {
@@ -7905,7 +7941,7 @@ var VoiceRenderer = class extends Renderer {
7905
7941
  return {
7906
7942
  element: await Promise.all(
7907
7943
  splitMessages.map(
7908
- async (text) => (0, import_koishi24.h)("message", await this._renderToVoice(text, options))
7944
+ async (text) => (0, import_koishi25.h)("message", await this._renderToVoice(text, options))
7909
7945
  )
7910
7946
  )
7911
7947
  };
@@ -7940,7 +7976,7 @@ var VoiceRenderer = class extends Renderer {
7940
7976
  )
7941
7977
  );
7942
7978
  }
7943
- schema = import_koishi24.Schema.const("voice").i18n({
7979
+ schema = import_koishi25.Schema.const("voice").i18n({
7944
7980
  "zh-CN": "将回复渲染为语音",
7945
7981
  "en-US": "Render as voice"
7946
7982
  });
@@ -7956,7 +7992,7 @@ var VoiceStreamSession = class extends BufferedRenderStreamSession {
7956
7992
  }
7957
7993
  async renderText(text) {
7958
7994
  return [
7959
- this.options.split && this.options.split !== "none" ? (0, import_koishi24.h)("message", await this.render(text)) : await this.render(text)
7995
+ this.options.split && this.options.split !== "none" ? (0, import_koishi25.h)("message", await this.render(text)) : await this.render(text)
7960
7996
  ];
7961
7997
  }
7962
7998
  };
@@ -8002,7 +8038,7 @@ var DefaultRenderer = class {
8002
8038
  for (const msg of message.additionalReplyMessages) {
8003
8039
  const elements = await rawRenderer.render(msg, options).then((r) => r.element);
8004
8040
  result.push({
8005
- element: (0, import_koishi25.h)(
8041
+ element: (0, import_koishi26.h)(
8006
8042
  "message",
8007
8043
  { forward: true },
8008
8044
  Array.isArray(elements) ? elements : [elements]
@@ -8044,7 +8080,7 @@ var DefaultRenderer = class {
8044
8080
  for (const msg of message.additionalReplyMessages) {
8045
8081
  const elements = await rawRenderer.render(msg, options).then((r) => r.element);
8046
8082
  result.push([
8047
- (0, import_koishi25.h)(
8083
+ (0, import_koishi26.h)(
8048
8084
  "message",
8049
8085
  { forward: true },
8050
8086
  Array.isArray(elements) ? elements : [elements]
@@ -8071,7 +8107,7 @@ var DefaultRenderer = class {
8071
8107
  }
8072
8108
  this.ctx.schema.set(
8073
8109
  "output-mode",
8074
- import_koishi25.Schema.union(this._getAllRendererScheme())
8110
+ import_koishi26.Schema.union(this._getAllRendererScheme())
8075
8111
  );
8076
8112
  }
8077
8113
  _getAllRendererScheme() {
@@ -8131,7 +8167,7 @@ function setupEntryPoint(ctx, config, disposables) {
8131
8167
  setupMiddleware(ctx2);
8132
8168
  });
8133
8169
  }, "entryPointPlugin");
8134
- const entryPointDisposable = (0, import_koishi27.forkScopeToDisposable)(
8170
+ const entryPointDisposable = (0, import_koishi28.forkScopeToDisposable)(
8135
8171
  ctx.plugin(
8136
8172
  {
8137
8173
  apply: entryPointPlugin,
@@ -8182,7 +8218,7 @@ function setupMiddleware(ctx) {
8182
8218
  __name(setupMiddleware, "setupMiddleware");
8183
8219
  function setupLogger(config) {
8184
8220
  if (config.isLog) {
8185
- (0, import_logger7.setLoggerLevel)(import_koishi26.Logger.DEBUG);
8221
+ (0, import_logger7.setLoggerLevel)(import_koishi27.Logger.DEBUG);
8186
8222
  }
8187
8223
  }
8188
8224
  __name(setupLogger, "setupLogger");
@@ -8202,7 +8238,7 @@ function setupProxy(ctx, config) {
8202
8238
  }
8203
8239
  __name(setupProxy, "setupProxy");
8204
8240
  function setupServices(ctx, config, disposables) {
8205
- disposables.push((0, import_koishi27.forkScopeToDisposable)(ctx.plugin(import_chat2.ChatLunaService, config)));
8241
+ disposables.push((0, import_koishi28.forkScopeToDisposable)(ctx.plugin(import_chat2.ChatLunaService, config)));
8206
8242
  }
8207
8243
  __name(setupServices, "setupServices");
8208
8244
  function setupPermissions(ctx, disposables) {
@@ -8273,7 +8309,7 @@ async function setupAutoArchive(ctx, config) {
8273
8309
  await execute();
8274
8310
  ctx.setInterval(async () => {
8275
8311
  await execute();
8276
- }, import_koishi26.Time.minute * 5);
8312
+ }, import_koishi27.Time.minute * 5);
8277
8313
  }
8278
8314
  __name(setupAutoArchive, "setupAutoArchive");
8279
8315
  async function setupAutoPurgeArchive(ctx, config) {
@@ -8336,7 +8372,7 @@ async function setupAutoPurgeArchive(ctx, config) {
8336
8372
  await execute();
8337
8373
  ctx.setInterval(async () => {
8338
8374
  await execute();
8339
- }, import_koishi26.Time.minute * 10);
8375
+ }, import_koishi27.Time.minute * 10);
8340
8376
  }
8341
8377
  __name(setupAutoPurgeArchive, "setupAutoPurgeArchive");
8342
8378
  async function dedupeConstraintNames(ctx) {