koishi-plugin-chatluna-toolbox 0.0.5 → 0.0.6
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.js +309 -288
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -31,6 +31,7 @@ __export(index_exports, {
|
|
|
31
31
|
apply: () => apply,
|
|
32
32
|
callOneBotAPI: () => callOneBotAPI,
|
|
33
33
|
createBotInfoProvider: () => createBotInfoProvider,
|
|
34
|
+
createCharacterTempXmlRuntime: () => createCharacterTempXmlRuntime,
|
|
34
35
|
createDeleteMessageTool: () => createDeleteMessageTool,
|
|
35
36
|
createGroupInfoProvider: () => createGroupInfoProvider,
|
|
36
37
|
createLogger: () => createLogger,
|
|
@@ -40,12 +41,12 @@ __export(index_exports, {
|
|
|
40
41
|
createSetMsgEmojiTool: () => createSetMsgEmojiTool,
|
|
41
42
|
createSetProfileTool: () => createSetProfileTool,
|
|
42
43
|
createUserInfoProvider: () => createUserInfoProvider,
|
|
43
|
-
|
|
44
|
+
createXmlProcessor: () => createXmlProcessor,
|
|
44
45
|
ensureOneBotSession: () => ensureOneBotSession,
|
|
45
46
|
getSession: () => getSession,
|
|
46
47
|
inject: () => inject,
|
|
47
48
|
name: () => name,
|
|
48
|
-
|
|
49
|
+
parseSelfClosingXmlTags: () => parseSelfClosingXmlTags,
|
|
49
50
|
registerNativeTools: () => registerNativeTools,
|
|
50
51
|
registerVariables: () => registerVariables,
|
|
51
52
|
registerXmlTools: () => registerXmlTools,
|
|
@@ -64,22 +65,22 @@ var import_koishi = require("koishi");
|
|
|
64
65
|
var NativeToolsSchema = import_koishi.Schema.object({
|
|
65
66
|
enableNapCatProtocol: import_koishi.Schema.boolean().default(true).description("\u542F\u7528 NapCat OneBot \u534F\u8BAE\uFF08\u4E0E LLBot \u4E8C\u9009\u4E00\uFF09"),
|
|
66
67
|
enableLlbotProtocol: import_koishi.Schema.boolean().default(false).description("\u542F\u7528 LLBot OneBot \u534F\u8BAE\uFF08\u4E0E NapCat \u4E8C\u9009\u4E00\uFF09"),
|
|
67
|
-
enablePokeTool: import_koishi.Schema.boolean().default(false).description("\u6CE8\u518C ChatLuna \u5DE5\u5177\uFF1A\u6233\u4E00\u6233\uFF08\
|
|
68
|
+
enablePokeTool: import_koishi.Schema.boolean().default(false).description("\u6CE8\u518C ChatLuna \u5DE5\u5177\uFF1A\u6233\u4E00\u6233\uFF08\u4E0E XML\u5DE5\u5177 \u4E8C\u9009\u4E00\uFF09"),
|
|
68
69
|
pokeToolName: import_koishi.Schema.string().default("poke_user").description("ChatLuna \u5DE5\u5177\u540D\u79F0\uFF1A\u6233\u4E00\u6233"),
|
|
69
70
|
enableSetSelfProfileTool: import_koishi.Schema.boolean().default(false).description("\u6CE8\u518C ChatLuna \u5DE5\u5177\uFF1A\u4FEE\u6539\u81EA\u8EAB\u8D26\u6237\u4FE1\u606F"),
|
|
70
71
|
setSelfProfileToolName: import_koishi.Schema.string().default("set_self_profile").description("ChatLuna \u5DE5\u5177\u540D\u79F0\uFF1A\u4FEE\u6539\u81EA\u8EAB\u8D26\u6237\u4FE1\u606F\uFF08\u652F\u6301\u6635\u79F0/\u7B7E\u540D/\u6027\u522B\uFF09"),
|
|
71
72
|
enableSetGroupCardTool: import_koishi.Schema.boolean().default(false).description("\u6CE8\u518C ChatLuna \u5DE5\u5177\uFF1A\u4FEE\u6539\u7FA4\u6210\u5458\u6635\u79F0"),
|
|
72
73
|
setGroupCardToolName: import_koishi.Schema.string().default("set_group_card").description("ChatLuna \u5DE5\u5177\u540D\u79F0\uFF1A\u4FEE\u6539\u7FA4\u6210\u5458\u6635\u79F0"),
|
|
73
|
-
enableSetMsgEmojiTool: import_koishi.Schema.boolean().default(false).description("\u6CE8\u518C ChatLuna \u5DE5\u5177\uFF1A\u7ED9\u6D88\u606F\u6DFB\u52A0\u8868\u60C5\uFF08\u9700 chatluna-character \u5F00\u542F enableMessageId\uFF0C\
|
|
74
|
+
enableSetMsgEmojiTool: import_koishi.Schema.boolean().default(false).description("\u6CE8\u518C ChatLuna \u5DE5\u5177\uFF1A\u7ED9\u6D88\u606F\u6DFB\u52A0\u8868\u60C5\uFF08\u9700 chatluna-character \u5F00\u542F enableMessageId\uFF0C\u4E0E XML\u5DE5\u5177 \u4E8C\u9009\u4E00\uFF0C\u8868\u60C5\u5BF9\u7167\u8868\uFF1Ahttps://bot.q.qq.com/wiki/develop/pythonsdk/model/emoji.html \uFF09"),
|
|
74
75
|
setMsgEmojiToolName: import_koishi.Schema.string().default("set_msg_emoji").description("ChatLuna \u5DE5\u5177\u540D\u79F0\uFF1A\u7ED9\u6D88\u606F\u6DFB\u52A0\u8868\u60C5"),
|
|
75
|
-
enableDeleteMessageTool: import_koishi.Schema.boolean().default(false).description("\u6CE8\u518C ChatLuna \u5DE5\u5177\uFF1A\u64A4\u56DE\u6D88\u606F\uFF08\u9700 chatluna-character \u5F00\u542F enableMessageId\uFF0C\
|
|
76
|
+
enableDeleteMessageTool: import_koishi.Schema.boolean().default(false).description("\u6CE8\u518C ChatLuna \u5DE5\u5177\uFF1A\u64A4\u56DE\u6D88\u606F\uFF08\u9700 chatluna-character \u5F00\u542F enableMessageId\uFF0C\u4E0E XML\u5DE5\u5177 \u4E8C\u9009\u4E00\uFF09"),
|
|
76
77
|
deleteMessageToolName: import_koishi.Schema.string().default("delete_msg").description("ChatLuna \u5DE5\u5177\u540D\u79F0\uFF1A\u64A4\u56DE\u6D88\u606F")
|
|
77
78
|
}).description("\u539F\u751F\u5DE5\u5177");
|
|
78
79
|
|
|
79
80
|
// src/schema/xml-tools.ts
|
|
80
81
|
var import_koishi2 = require("koishi");
|
|
81
82
|
var DEFAULT_XML_REFERENCE_PROMPT = `## \u52A8\u4F5C\u6307\u4EE4
|
|
82
|
-
\u4F60\u53EF\u4EE5\u6839\u636E\u9700\u8981\
|
|
83
|
+
\u4F60\u53EF\u4EE5\u6839\u636E\u9700\u8981\u5728\u6A21\u578B\u56DE\u590D\u4E2D\u8F93\u51FA\u4E00\u4E2A\u72EC\u7ACB\u7684 <actions> \u5143\u7D20\u3002\u5B83\u7528\u4E8E\u6267\u884C\u975E\u8BED\u8A00\u7684\u7CFB\u7EDF\u6307\u4EE4\u3002\u5982\u679C\u4E0D\u9700\u8981\u6267\u884C\u4EFB\u4F55\u52A8\u4F5C\uFF0C\u8BF7\u7701\u7565\u6B64\u5143\u7D20\u3002
|
|
83
84
|
1. \u6233\u4E00\u6233: <poke id=""/>
|
|
84
85
|
- id: user_id
|
|
85
86
|
- \u9002\u7528\u573A\u666F:
|
|
@@ -111,10 +112,12 @@ var DEFAULT_XML_REFERENCE_PROMPT = `## \u52A8\u4F5C\u6307\u4EE4
|
|
|
111
112
|
</actions>
|
|
112
113
|
\`\`\``;
|
|
113
114
|
var XmlToolsSchema = import_koishi2.Schema.object({
|
|
114
|
-
enablePokeXmlTool: import_koishi2.Schema.boolean().default(false).description("\u542F\u7528 XML \u5F62\u5F0F\u7684\u6233\u4E00\u6233\u8C03\u7528"),
|
|
115
|
-
enableEmojiXmlTool: import_koishi2.Schema.boolean().default(false).description(
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
enablePokeXmlTool: import_koishi2.Schema.boolean().default(false).description("\u542F\u7528 XML \u5F62\u5F0F\u7684\u6233\u4E00\u6233\u8C03\u7528\uFF08\u4E0E \u539F\u751F\u5DE5\u5177 \u4E8C\u9009\u4E00\uFF09"),
|
|
116
|
+
enableEmojiXmlTool: import_koishi2.Schema.boolean().default(false).description(
|
|
117
|
+
"\u542F\u7528 XML \u5F62\u5F0F\u7684\u6D88\u606F\u8868\u60C5\u8C03\u7528\uFF0C\uFF08\u9700 chatluna-character \u5F00\u542F enableMessageId\uFF0C\u4E0E \u539F\u751F\u5DE5\u5177 \u4E8C\u9009\u4E00\uFF0Cemoji_id \u5BF9\u7167\u8868\uFF1Ahttps://bot.q.qq.com/wiki/develop/pythonsdk/model/emoji.html \uFF09"
|
|
118
|
+
),
|
|
119
|
+
enableDeleteXmlTool: import_koishi2.Schema.boolean().default(false).description("\u542F\u7528 XML \u5F62\u5F0F\u7684\u6D88\u606F\u64A4\u56DE\u8C03\u7528\uFF08\u9700 chatluna-character \u5F00\u542F enableMessageId\uFF0C\u4E0E \u539F\u751F\u5DE5\u5177 \u4E8C\u9009\u4E00\uFF09"),
|
|
120
|
+
referencePrompt: import_koishi2.Schema.string().role("textarea").default(DEFAULT_XML_REFERENCE_PROMPT).description("\u6A21\u578B\u56DE\u590D XML \u53C2\u8003\u63D0\u793A\u8BCD\uFF0C\u81EA\u884C\u5199\u5165\u63D0\u793A\u8BCD\u4E2D\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u6CE8\u5165")
|
|
118
121
|
}).description("XML \u5DE5\u5177");
|
|
119
122
|
|
|
120
123
|
// src/schema/variables.ts
|
|
@@ -600,311 +603,315 @@ function registerNativeTools(deps) {
|
|
|
600
603
|
}
|
|
601
604
|
}
|
|
602
605
|
|
|
603
|
-
// src/features/xml-tools/
|
|
604
|
-
function
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
let startupHandle = null;
|
|
615
|
-
const responseRetryHandles = /* @__PURE__ */ new Map();
|
|
616
|
-
let activeService = null;
|
|
617
|
-
let activeLogger = null;
|
|
618
|
-
let originalDebug = null;
|
|
619
|
-
let collectorBound = false;
|
|
620
|
-
const restore = () => {
|
|
621
|
-
if (activeLogger && originalDebug) {
|
|
622
|
-
activeLogger.debug = originalDebug;
|
|
623
|
-
}
|
|
624
|
-
activeLogger = null;
|
|
625
|
-
originalDebug = null;
|
|
626
|
-
};
|
|
627
|
-
const isActive = () => {
|
|
628
|
-
const characterService = ctx.chatluna_character;
|
|
629
|
-
const debugFn = characterService?.logger?.debug;
|
|
630
|
-
return Boolean(debugFn?.[RAW_INTERCEPTOR_TAG]);
|
|
631
|
-
};
|
|
632
|
-
const resolveSession = () => {
|
|
633
|
-
while (pendingSessions.length > 100) pendingSessions.shift();
|
|
634
|
-
const now = Date.now();
|
|
635
|
-
while (pendingSessions.length > 0 && now - pendingSessions[0].timestamp > 12e3) {
|
|
636
|
-
pendingSessions.shift();
|
|
637
|
-
}
|
|
638
|
-
if (pendingSessions.length === 0) {
|
|
639
|
-
return (currentGuildId ? sessionMap.get(currentGuildId) : null) || lastSession || null;
|
|
640
|
-
}
|
|
641
|
-
const contextKeys = /* @__PURE__ */ new Set();
|
|
642
|
-
for (let i = 0; i < pendingSessions.length; i++) {
|
|
643
|
-
contextKeys.add(pendingSessions[i].key || "__null__");
|
|
606
|
+
// src/features/xml-tools/parser.ts
|
|
607
|
+
function parseSelfClosingXmlTags(text, tagName) {
|
|
608
|
+
const tags = Array.from(
|
|
609
|
+
text.matchAll(new RegExp(`<${tagName}\\b([^>]*)\\/>`, "gi"))
|
|
610
|
+
);
|
|
611
|
+
if (!tags.length) return [];
|
|
612
|
+
return tags.map((tag) => {
|
|
613
|
+
const attrText = String(tag[1] || "");
|
|
614
|
+
const attrs = {};
|
|
615
|
+
for (const pair of attrText.matchAll(/([a-zA-Z_][\w-]*)="([^"]*)"/g)) {
|
|
616
|
+
attrs[pair[1]] = pair[2];
|
|
644
617
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
618
|
+
return attrs;
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
// src/features/xml-tools/processor.ts
|
|
623
|
+
function createXmlProcessor(deps) {
|
|
624
|
+
const {
|
|
625
|
+
config,
|
|
626
|
+
protocol,
|
|
627
|
+
log,
|
|
628
|
+
sendPoke: runPoke = sendPoke,
|
|
629
|
+
sendMsgEmoji: runEmoji = sendMsgEmoji,
|
|
630
|
+
sendDeleteMessage: runDelete = sendDeleteMessage
|
|
631
|
+
} = deps;
|
|
632
|
+
return async ({ response, session }) => {
|
|
633
|
+
const content = String(response || "").trim();
|
|
634
|
+
if (!content) return false;
|
|
635
|
+
const pokeTags = parseSelfClosingXmlTags(content, "poke");
|
|
636
|
+
const emojiTags = parseSelfClosingXmlTags(content, "emoji");
|
|
637
|
+
const deleteTags = parseSelfClosingXmlTags(content, "delete");
|
|
638
|
+
let handled = false;
|
|
639
|
+
if (config.enablePokeXmlTool && pokeTags.length > 0) {
|
|
640
|
+
if (!session) {
|
|
641
|
+
log?.("warn", "\u68C0\u6D4B\u5230\u6233\u4E00\u6233\u6807\u8BB0\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587");
|
|
642
|
+
} else {
|
|
643
|
+
const userIds = pokeTags.map((attrs) => String(attrs.id || "").trim()).filter(Boolean);
|
|
644
|
+
if (userIds.length > 0) handled = true;
|
|
645
|
+
for (const userId of userIds) {
|
|
646
|
+
try {
|
|
647
|
+
await runPoke({ session, userId, protocol, log });
|
|
648
|
+
} catch (error) {
|
|
649
|
+
log?.("warn", "XML \u89E6\u53D1 poke \u5931\u8D25", error);
|
|
650
|
+
}
|
|
651
651
|
}
|
|
652
652
|
}
|
|
653
653
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
if (retryHandle) {
|
|
677
|
-
retryHandle();
|
|
678
|
-
responseRetryHandles.delete(responseId);
|
|
654
|
+
if (config.enableEmojiXmlTool && emojiTags.length > 0) {
|
|
655
|
+
if (!session) {
|
|
656
|
+
log?.("warn", "\u68C0\u6D4B\u5230\u8868\u60C5\u6807\u8BB0\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587");
|
|
657
|
+
} else {
|
|
658
|
+
const items = emojiTags.map((attrs) => ({
|
|
659
|
+
messageId: String(attrs.message_id || "").trim(),
|
|
660
|
+
emojiId: String(attrs.emoji_id || "").trim()
|
|
661
|
+
})).filter((item) => item.messageId && item.emojiId);
|
|
662
|
+
if (items.length > 0) handled = true;
|
|
663
|
+
for (const item of items) {
|
|
664
|
+
try {
|
|
665
|
+
await runEmoji({
|
|
666
|
+
session,
|
|
667
|
+
messageId: item.messageId,
|
|
668
|
+
emojiId: item.emojiId,
|
|
669
|
+
protocol,
|
|
670
|
+
log
|
|
671
|
+
});
|
|
672
|
+
} catch (error) {
|
|
673
|
+
log?.("warn", "XML \u89E6\u53D1\u8868\u60C5\u5931\u8D25", error);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
679
676
|
}
|
|
680
677
|
}
|
|
681
|
-
|
|
682
|
-
};
|
|
683
|
-
const retryResponse = (responseId, response) => {
|
|
684
|
-
if (responseRetryHandles.has(responseId) || processedResponses.has(responseId))
|
|
685
|
-
return;
|
|
686
|
-
const handle = ctx.setTimeout(() => {
|
|
687
|
-
responseRetryHandles.delete(responseId);
|
|
688
|
-
if (processedResponses.has(responseId)) return;
|
|
689
|
-
const session = resolveSession();
|
|
678
|
+
if (config.enableDeleteXmlTool && deleteTags.length > 0) {
|
|
690
679
|
if (!session) {
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
680
|
+
log?.("warn", "\u68C0\u6D4B\u5230\u64A4\u56DE\u6807\u8BB0\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587");
|
|
681
|
+
} else {
|
|
682
|
+
const messageIds = deleteTags.map((attrs) => String(attrs.message_id || "").trim()).filter(Boolean);
|
|
683
|
+
if (messageIds.length > 0) handled = true;
|
|
684
|
+
for (const messageId of messageIds) {
|
|
685
|
+
try {
|
|
686
|
+
await runDelete({ session, messageId, log });
|
|
687
|
+
} catch (error) {
|
|
688
|
+
log?.("warn", "XML \u89E6\u53D1\u64A4\u56DE\u5931\u8D25", error);
|
|
689
|
+
}
|
|
695
690
|
}
|
|
696
|
-
runResponse(responseId, response, null);
|
|
697
|
-
return;
|
|
698
691
|
}
|
|
699
|
-
runResponse(responseId, response, session);
|
|
700
|
-
}, 200);
|
|
701
|
-
responseRetryHandles.set(responseId, handle);
|
|
702
|
-
};
|
|
703
|
-
const attach = () => {
|
|
704
|
-
const characterService = ctx.chatluna_character;
|
|
705
|
-
if (!characterService) return false;
|
|
706
|
-
if (activeService !== characterService) {
|
|
707
|
-
activeService = characterService;
|
|
708
|
-
collectorBound = false;
|
|
709
|
-
}
|
|
710
|
-
if (!collectorBound && typeof characterService.collect === "function") {
|
|
711
|
-
characterService.collect(async (session) => {
|
|
712
|
-
const guildId = session?.guildId || session?.channelId || session?.userId || null;
|
|
713
|
-
currentGuildId = guildId;
|
|
714
|
-
if (guildId) sessionMap.set(guildId, session);
|
|
715
|
-
lastSession = session;
|
|
716
|
-
pendingSessions.push({ key: guildId, session, timestamp: Date.now() });
|
|
717
|
-
});
|
|
718
|
-
collectorBound = true;
|
|
719
692
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
693
|
+
return handled;
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// src/features/xml-tools/temp-runtime.ts
|
|
698
|
+
var GET_TEMP_TAG = /* @__PURE__ */ Symbol.for("chatlunaToolboxXmlGetTempRuntime");
|
|
699
|
+
var GET_TEMP_ORIGINAL = /* @__PURE__ */ Symbol.for("chatlunaToolboxXmlOriginalGetTemp");
|
|
700
|
+
var GET_TEMP_LISTENERS = /* @__PURE__ */ Symbol.for("chatlunaToolboxXmlGetTempListeners");
|
|
701
|
+
var PUSH_DISPATCHER = /* @__PURE__ */ Symbol.for("chatlunaToolboxXmlPushDispatcher");
|
|
702
|
+
function getMessageType(message) {
|
|
703
|
+
if (!message) return "";
|
|
704
|
+
if (typeof message._getType === "function") {
|
|
705
|
+
return String(message._getType() || "").trim().toLowerCase();
|
|
706
|
+
}
|
|
707
|
+
return String(message.type || message.role || "").trim().toLowerCase();
|
|
708
|
+
}
|
|
709
|
+
function isAssistantMessage(message) {
|
|
710
|
+
const type = getMessageType(message);
|
|
711
|
+
return type === "ai" || type === "assistant";
|
|
712
|
+
}
|
|
713
|
+
function extractText(value) {
|
|
714
|
+
if (typeof value === "string") return value;
|
|
715
|
+
if (value == null) return "";
|
|
716
|
+
if (Array.isArray(value)) {
|
|
717
|
+
return value.map((item) => extractText(item)).join("");
|
|
718
|
+
}
|
|
719
|
+
if (typeof value !== "object") return "";
|
|
720
|
+
const record = value;
|
|
721
|
+
if (typeof record.text === "string") return record.text;
|
|
722
|
+
if (record.content !== void 0 && record.content !== value) {
|
|
723
|
+
return extractText(record.content);
|
|
724
|
+
}
|
|
725
|
+
if (Array.isArray(record.children)) return extractText(record.children);
|
|
726
|
+
if (typeof record.attrs === "object" && record.attrs) {
|
|
727
|
+
const attrs = record.attrs;
|
|
728
|
+
if (typeof attrs.content === "string") return attrs.content;
|
|
729
|
+
if (typeof attrs.text === "string") return attrs.text;
|
|
730
|
+
}
|
|
731
|
+
return "";
|
|
732
|
+
}
|
|
733
|
+
function getResponseText(message) {
|
|
734
|
+
if (!isAssistantMessage(message)) return "";
|
|
735
|
+
return extractText(message?.content ?? message?.text).trim();
|
|
736
|
+
}
|
|
737
|
+
function getDispatcher(messages) {
|
|
738
|
+
return messages[PUSH_DISPATCHER] ?? null;
|
|
739
|
+
}
|
|
740
|
+
function setDispatcher(messages, dispatcher) {
|
|
741
|
+
const record = messages;
|
|
742
|
+
if (!dispatcher) {
|
|
743
|
+
delete record[PUSH_DISPATCHER];
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
Object.defineProperty(record, PUSH_DISPATCHER, {
|
|
747
|
+
value: dispatcher,
|
|
748
|
+
configurable: true,
|
|
749
|
+
enumerable: false,
|
|
750
|
+
writable: true
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
function attachDispatcher(messages, log) {
|
|
754
|
+
const existing = getDispatcher(messages);
|
|
755
|
+
if (existing) return existing;
|
|
756
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
757
|
+
const processedMessages = /* @__PURE__ */ new WeakSet();
|
|
758
|
+
const originalPush = messages.push;
|
|
759
|
+
const patchedPush = function patchedPush2(...items) {
|
|
760
|
+
const result = originalPush.apply(this, items);
|
|
761
|
+
for (const item of items) {
|
|
762
|
+
if (!item || typeof item !== "object") continue;
|
|
763
|
+
const message = item;
|
|
764
|
+
if (!isAssistantMessage(message)) continue;
|
|
765
|
+
if (processedMessages.has(item)) continue;
|
|
766
|
+
const response = getResponseText(message);
|
|
767
|
+
if (!response) continue;
|
|
768
|
+
processedMessages.add(item);
|
|
769
|
+
for (const listener of Array.from(listeners)) {
|
|
770
|
+
try {
|
|
771
|
+
listener(message);
|
|
772
|
+
} catch (error) {
|
|
773
|
+
log?.("warn", "\u5904\u7406 XML completionMessages \u76D1\u542C\u5668\u5931\u8D25", error);
|
|
742
774
|
}
|
|
743
|
-
|
|
744
|
-
};
|
|
745
|
-
wrapped[RAW_INTERCEPTOR_TAG] = true;
|
|
746
|
-
loggerService.debug = wrapped;
|
|
747
|
-
activeLogger = loggerService;
|
|
748
|
-
originalDebug = raw;
|
|
775
|
+
}
|
|
749
776
|
}
|
|
750
|
-
return
|
|
777
|
+
return result;
|
|
751
778
|
};
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
779
|
+
const dispatcher = {
|
|
780
|
+
messages,
|
|
781
|
+
originalPush,
|
|
782
|
+
patchedPush,
|
|
783
|
+
listeners,
|
|
784
|
+
processedMessages
|
|
756
785
|
};
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
786
|
+
messages.push = patchedPush;
|
|
787
|
+
setDispatcher(messages, dispatcher);
|
|
788
|
+
return dispatcher;
|
|
789
|
+
}
|
|
790
|
+
function restoreDispatcher(dispatcher) {
|
|
791
|
+
if (dispatcher.messages.push === dispatcher.patchedPush) {
|
|
792
|
+
dispatcher.messages.push = dispatcher.originalPush;
|
|
793
|
+
}
|
|
794
|
+
setDispatcher(dispatcher.messages, null);
|
|
795
|
+
}
|
|
796
|
+
function registerGetTempListener(service, listener) {
|
|
797
|
+
const getTemp = service.getTemp;
|
|
798
|
+
if (typeof getTemp !== "function") return null;
|
|
799
|
+
const serviceRecord = service;
|
|
800
|
+
let listeners = serviceRecord[GET_TEMP_LISTENERS];
|
|
801
|
+
if (!listeners) {
|
|
802
|
+
listeners = /* @__PURE__ */ new Set();
|
|
803
|
+
serviceRecord[GET_TEMP_LISTENERS] = listeners;
|
|
804
|
+
}
|
|
805
|
+
if (!serviceRecord[GET_TEMP_TAG]) {
|
|
806
|
+
Object.defineProperty(serviceRecord, GET_TEMP_ORIGINAL, {
|
|
807
|
+
value: getTemp,
|
|
808
|
+
configurable: true,
|
|
809
|
+
enumerable: false,
|
|
810
|
+
writable: true
|
|
811
|
+
});
|
|
812
|
+
service.getTemp = async (...args) => {
|
|
813
|
+
const originalGetTemp = serviceRecord[GET_TEMP_ORIGINAL];
|
|
814
|
+
const temp = await originalGetTemp?.apply(
|
|
815
|
+
service,
|
|
816
|
+
args
|
|
817
|
+
);
|
|
818
|
+
const activeListeners = serviceRecord[GET_TEMP_LISTENERS];
|
|
819
|
+
const session = args[0] && typeof args[0] === "object" ? args[0] : null;
|
|
820
|
+
if (temp && activeListeners?.size) {
|
|
821
|
+
for (const handler of Array.from(activeListeners)) {
|
|
822
|
+
handler(temp, session);
|
|
823
|
+
}
|
|
768
824
|
}
|
|
769
|
-
|
|
825
|
+
return temp;
|
|
826
|
+
};
|
|
827
|
+
serviceRecord[GET_TEMP_TAG] = true;
|
|
828
|
+
}
|
|
829
|
+
listeners.add(listener);
|
|
830
|
+
return () => {
|
|
831
|
+
const currentListeners = serviceRecord[GET_TEMP_LISTENERS];
|
|
832
|
+
currentListeners?.delete(listener);
|
|
833
|
+
if (currentListeners?.size) return;
|
|
834
|
+
const originalGetTemp = serviceRecord[GET_TEMP_ORIGINAL];
|
|
835
|
+
if (originalGetTemp) service.getTemp = originalGetTemp;
|
|
836
|
+
delete serviceRecord[GET_TEMP_ORIGINAL];
|
|
837
|
+
delete serviceRecord[GET_TEMP_TAG];
|
|
838
|
+
delete serviceRecord[GET_TEMP_LISTENERS];
|
|
770
839
|
};
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
840
|
+
}
|
|
841
|
+
function createCharacterTempXmlRuntime(params) {
|
|
842
|
+
const { getCharacterService, processModelResponse, log } = params;
|
|
843
|
+
let attachedDispatchers = [];
|
|
844
|
+
let stopListening = null;
|
|
845
|
+
const compactAttachedDispatchers = () => {
|
|
846
|
+
attachedDispatchers = attachedDispatchers.filter(
|
|
847
|
+
(entry) => Boolean(entry.ref.deref())
|
|
848
|
+
);
|
|
849
|
+
};
|
|
850
|
+
const hasAttachedListener = (dispatcher) => {
|
|
851
|
+
compactAttachedDispatchers();
|
|
852
|
+
return attachedDispatchers.some(
|
|
853
|
+
(entry) => entry.ref.deref() === dispatcher
|
|
854
|
+
);
|
|
780
855
|
};
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
856
|
+
const detachDispatcherListener = (entry) => {
|
|
857
|
+
const dispatcher = entry.ref.deref();
|
|
858
|
+
if (!dispatcher) return;
|
|
859
|
+
dispatcher.listeners.delete(entry.listener);
|
|
860
|
+
if (dispatcher.listeners.size === 0) restoreDispatcher(dispatcher);
|
|
786
861
|
};
|
|
787
|
-
const
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
862
|
+
const handleTemp = (temp, session) => {
|
|
863
|
+
const messages = temp.completionMessages;
|
|
864
|
+
if (!Array.isArray(messages) || typeof messages.push !== "function") return;
|
|
865
|
+
const dispatcher = attachDispatcher(messages, log);
|
|
866
|
+
if (hasAttachedListener(dispatcher)) return;
|
|
867
|
+
const listener = (message) => {
|
|
868
|
+
const response = getResponseText(message);
|
|
869
|
+
if (!response) return;
|
|
870
|
+
void processModelResponse({ response, session }).catch((error) => {
|
|
871
|
+
log?.("warn", "\u5904\u7406 XML \u6A21\u578B\u54CD\u5E94\u5931\u8D25", error);
|
|
872
|
+
});
|
|
873
|
+
};
|
|
874
|
+
dispatcher.listeners.add(listener);
|
|
875
|
+
attachedDispatchers.push({ ref: new WeakRef(dispatcher), listener });
|
|
791
876
|
};
|
|
792
877
|
return {
|
|
793
878
|
start: () => {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
startFastRetry();
|
|
879
|
+
if (stopListening) return true;
|
|
880
|
+
const service = getCharacterService();
|
|
881
|
+
if (!service) return false;
|
|
882
|
+
const detach = registerGetTempListener(service, handleTemp);
|
|
883
|
+
if (!detach) return false;
|
|
884
|
+
stopListening = () => {
|
|
885
|
+
compactAttachedDispatchers();
|
|
886
|
+
for (const entry of attachedDispatchers) {
|
|
887
|
+
detachDispatcherListener(entry);
|
|
804
888
|
}
|
|
805
|
-
|
|
806
|
-
|
|
889
|
+
attachedDispatchers = [];
|
|
890
|
+
detach();
|
|
891
|
+
stopListening = null;
|
|
892
|
+
};
|
|
893
|
+
return true;
|
|
807
894
|
},
|
|
808
895
|
stop: () => {
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
}
|
|
813
|
-
stopFastRetry();
|
|
814
|
-
stopMonitor();
|
|
815
|
-
for (const handle of responseRetryHandles.values()) handle();
|
|
816
|
-
responseRetryHandles.clear();
|
|
817
|
-
processedResponses.clear();
|
|
818
|
-
restore();
|
|
819
|
-
sessionMap.clear();
|
|
820
|
-
pendingSessions.length = 0;
|
|
821
|
-
currentGuildId = null;
|
|
822
|
-
lastSession = null;
|
|
823
|
-
activeService = null;
|
|
824
|
-
}
|
|
825
|
-
};
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
// src/features/xml-tools/parser.ts
|
|
829
|
-
function unique(values) {
|
|
830
|
-
return Array.from(new Set(values.map((item) => item.trim()).filter(Boolean)));
|
|
831
|
-
}
|
|
832
|
-
function parseXmlActions(response) {
|
|
833
|
-
const pokeMatches = Array.from(response.matchAll(/<poke\s+id="([^"]+)"\s*\/>/gi));
|
|
834
|
-
const emojiMatches = Array.from(
|
|
835
|
-
response.matchAll(/<emoji\s+message_id="([^"]+)"\s+emoji_id="([^"]+)"\s*\/>/gi)
|
|
836
|
-
);
|
|
837
|
-
const deleteMatches = Array.from(response.matchAll(/<delete\s+message_id="([^"]+)"\s*\/?>/gi));
|
|
838
|
-
return {
|
|
839
|
-
pokeUserIds: unique(pokeMatches.map((match) => String(match[1] || ""))),
|
|
840
|
-
emojis: emojiMatches.map((match) => ({
|
|
841
|
-
messageId: String(match[1] || "").trim(),
|
|
842
|
-
emojiId: String(match[2] || "").trim()
|
|
843
|
-
})).filter((item) => item.messageId && item.emojiId),
|
|
844
|
-
deleteMessageIds: unique(deleteMatches.map((match) => String(match[1] || "")))
|
|
896
|
+
stopListening?.();
|
|
897
|
+
},
|
|
898
|
+
isActive: () => Boolean(stopListening)
|
|
845
899
|
};
|
|
846
900
|
}
|
|
847
901
|
|
|
848
902
|
// src/features/xml-tools/register.ts
|
|
849
903
|
function registerXmlTools(deps) {
|
|
850
904
|
const { ctx, config, protocol, log } = deps;
|
|
851
|
-
const
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
const actions = parseXmlActions(response);
|
|
857
|
-
let handled = false;
|
|
858
|
-
if (config.enablePokeXmlTool && actions.pokeUserIds.length > 0) {
|
|
859
|
-
if (!session) {
|
|
860
|
-
log?.("warn", "\u68C0\u6D4B\u5230\u6233\u4E00\u6233\u6807\u8BB0\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587");
|
|
861
|
-
} else {
|
|
862
|
-
handled = true;
|
|
863
|
-
for (const userId of actions.pokeUserIds) {
|
|
864
|
-
void sendPoke({ session, userId, protocol, log }).catch((error) => {
|
|
865
|
-
log?.("warn", "XML \u89E6\u53D1 poke \u5931\u8D25", error);
|
|
866
|
-
});
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
if (config.enableEmojiXmlTool && actions.emojis.length > 0) {
|
|
871
|
-
if (!session) {
|
|
872
|
-
log?.("warn", "\u68C0\u6D4B\u5230\u8868\u60C5\u6807\u8BB0\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587");
|
|
873
|
-
} else {
|
|
874
|
-
handled = true;
|
|
875
|
-
for (const item of actions.emojis) {
|
|
876
|
-
void sendMsgEmoji({
|
|
877
|
-
session,
|
|
878
|
-
messageId: item.messageId,
|
|
879
|
-
emojiId: item.emojiId,
|
|
880
|
-
protocol,
|
|
881
|
-
log
|
|
882
|
-
}).catch((error) => {
|
|
883
|
-
log?.("warn", "XML \u89E6\u53D1\u8868\u60C5\u5931\u8D25", error);
|
|
884
|
-
});
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
if (config.enableDeleteXmlTool && actions.deleteMessageIds.length > 0) {
|
|
889
|
-
if (!session) {
|
|
890
|
-
log?.("warn", "\u68C0\u6D4B\u5230\u64A4\u56DE\u6807\u8BB0\u4F46\u7F3A\u5C11\u4F1A\u8BDD\u4E0A\u4E0B\u6587");
|
|
891
|
-
} else {
|
|
892
|
-
handled = true;
|
|
893
|
-
for (const messageId of actions.deleteMessageIds) {
|
|
894
|
-
void sendDeleteMessage({ session, messageId, log }).catch(
|
|
895
|
-
(error) => {
|
|
896
|
-
log?.("warn", "XML \u89E6\u53D1\u64A4\u56DE\u5931\u8D25", error);
|
|
897
|
-
}
|
|
898
|
-
);
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
return handled;
|
|
903
|
-
}
|
|
905
|
+
const processor = createXmlProcessor({ config, protocol, log });
|
|
906
|
+
const runtime = createCharacterTempXmlRuntime({
|
|
907
|
+
getCharacterService: () => ctx.chatluna_character,
|
|
908
|
+
processModelResponse: processor,
|
|
909
|
+
log
|
|
904
910
|
});
|
|
905
911
|
return {
|
|
906
|
-
start: () =>
|
|
907
|
-
stop: () =>
|
|
912
|
+
start: () => runtime.start(),
|
|
913
|
+
stop: () => runtime.stop(),
|
|
914
|
+
isActive: () => runtime.isActive()
|
|
908
915
|
};
|
|
909
916
|
}
|
|
910
917
|
|
|
@@ -1509,22 +1516,35 @@ function apply(ctx, config) {
|
|
|
1509
1516
|
};
|
|
1510
1517
|
const log = createLogger(ctx, config);
|
|
1511
1518
|
let xmlRuntime = null;
|
|
1519
|
+
let characterCtx = null;
|
|
1512
1520
|
const initializeServices = async () => {
|
|
1513
1521
|
log("info", "toolbox \u521D\u59CB\u5316\u5F00\u59CB");
|
|
1514
1522
|
registerVariables({ ctx, config, log });
|
|
1515
1523
|
const protocol = resolveOneBotProtocol(config, log);
|
|
1516
1524
|
registerNativeTools({ ctx, config, plugin, protocol, log });
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
xmlRuntime.start();
|
|
1525
|
+
xmlRuntime = registerXmlTools({ ctx, config, protocol, log });
|
|
1526
|
+
if (characterCtx && xmlRuntime.start()) {
|
|
1520
1527
|
log("info", "XML \u5DE5\u5177\u5DF2\u542F\u7528");
|
|
1521
1528
|
}
|
|
1522
1529
|
log("info", "toolbox \u521D\u59CB\u5316\u5B8C\u6210");
|
|
1523
1530
|
};
|
|
1524
1531
|
const dispose = () => {
|
|
1532
|
+
characterCtx = null;
|
|
1525
1533
|
xmlRuntime?.stop();
|
|
1526
1534
|
xmlRuntime = null;
|
|
1527
1535
|
};
|
|
1536
|
+
if (config.enablePokeXmlTool || config.enableEmojiXmlTool || config.enableDeleteXmlTool) {
|
|
1537
|
+
ctx.inject(["chatluna_character"], (innerCtx) => {
|
|
1538
|
+
characterCtx = innerCtx;
|
|
1539
|
+
if (!xmlRuntime) return;
|
|
1540
|
+
const started = xmlRuntime.start();
|
|
1541
|
+
if (started) log("info", "XML \u5DE5\u5177\u5DF2\u542F\u7528");
|
|
1542
|
+
innerCtx.on("dispose", () => {
|
|
1543
|
+
if (characterCtx === innerCtx) characterCtx = null;
|
|
1544
|
+
xmlRuntime?.stop();
|
|
1545
|
+
});
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1528
1548
|
ctx.on("dispose", dispose);
|
|
1529
1549
|
if (ctx.root.lifecycle.isActive) {
|
|
1530
1550
|
void initializeServices();
|
|
@@ -1547,6 +1567,7 @@ function apply(ctx, config) {
|
|
|
1547
1567
|
apply,
|
|
1548
1568
|
callOneBotAPI,
|
|
1549
1569
|
createBotInfoProvider,
|
|
1570
|
+
createCharacterTempXmlRuntime,
|
|
1550
1571
|
createDeleteMessageTool,
|
|
1551
1572
|
createGroupInfoProvider,
|
|
1552
1573
|
createLogger,
|
|
@@ -1556,12 +1577,12 @@ function apply(ctx, config) {
|
|
|
1556
1577
|
createSetMsgEmojiTool,
|
|
1557
1578
|
createSetProfileTool,
|
|
1558
1579
|
createUserInfoProvider,
|
|
1559
|
-
|
|
1580
|
+
createXmlProcessor,
|
|
1560
1581
|
ensureOneBotSession,
|
|
1561
1582
|
getSession,
|
|
1562
1583
|
inject,
|
|
1563
1584
|
name,
|
|
1564
|
-
|
|
1585
|
+
parseSelfClosingXmlTags,
|
|
1565
1586
|
registerNativeTools,
|
|
1566
1587
|
registerVariables,
|
|
1567
1588
|
registerXmlTools,
|