koishi-plugin-chatluna-think-viewer 2.2.0 → 2.2.1
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/README.md +15 -15
- package/index.js +28 -28
- package/package.json +43 -43
package/README.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
# koishi-plugin-chatluna-think-viewer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
通过指令或关键词查看 `chatluna-character` 最近一次回复里的 `<think>` 思考内容,并提供输出拦截/撤回保护,防止模型把内部思考或异常格式直接发到群里。
|
|
4
4
|
|
|
5
5
|
## 功能
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
6
|
+
- 读取 `chatluna-character` 内存中的思考记录,支持指令和无前缀关键词触发。
|
|
7
|
+
- 可选私聊使用开关。
|
|
8
|
+
- **异常输出自动处理**:先发送、再检测;命中规则则按设置撤回(或直接阻断)。默认拦截 `<think>/<status>/<output>/<analysis>/<system>` 等标签、think/json/yaml 代码块。
|
|
9
|
+
- **关键词模式**:默认子串匹配(不区分大小写);可切换为正则模式。
|
|
10
|
+
- **严格输出模式**:可选,仅允许 `<output><message>…</message></output>` 结构,不符即撤回/阻断。
|
|
11
11
|
|
|
12
12
|
## 安装
|
|
13
13
|
```bash
|
|
14
14
|
npm install koishi-plugin-chatluna-think-viewer
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## 配置示例(koishi.yml)
|
|
18
18
|
```yaml
|
|
19
19
|
plugins:
|
|
20
20
|
chatluna-character: {}
|
|
@@ -24,12 +24,11 @@ plugins:
|
|
|
24
24
|
- 查看思考
|
|
25
25
|
allowPrivate: false
|
|
26
26
|
emptyMessage: 暂时没有可用的思考记录。
|
|
27
|
-
# 守卫配置(发送后检测再撤回)
|
|
28
27
|
guardEnabled: true
|
|
29
|
-
guardMode: recall
|
|
30
|
-
guardDelay: 1
|
|
31
|
-
guardKeywordMode: true
|
|
32
|
-
guardStrictOutputOnly: false
|
|
28
|
+
guardMode: recall # recall=先发后撤回;block=直接阻断
|
|
29
|
+
guardDelay: 1 # 撤回延迟(秒)
|
|
30
|
+
guardKeywordMode: true # true=子串匹配;false=正则匹配
|
|
31
|
+
guardStrictOutputOnly: false
|
|
33
32
|
guardForbiddenPatterns:
|
|
34
33
|
- '<think>'
|
|
35
34
|
- '<status>'
|
|
@@ -37,12 +36,13 @@ plugins:
|
|
|
37
36
|
```
|
|
38
37
|
|
|
39
38
|
## 使用
|
|
40
|
-
-
|
|
41
|
-
-
|
|
39
|
+
- 群里发送 `think` 或配置的关键词,查看最新 `<think>`;`think 2` 查看倒数第 2 条 AI 回复的思考。
|
|
40
|
+
- 如果最终发送的消息含异常标签/格式,守卫会按配置撤回或阻断,并在日志记录原因。
|
|
42
41
|
|
|
43
42
|
## 依赖
|
|
44
43
|
- koishi >= 4.18.0
|
|
45
44
|
- koishi-plugin-chatluna-character >= 0.0.180
|
|
46
45
|
|
|
47
|
-
##
|
|
46
|
+
## 许可证
|
|
48
47
|
MIT
|
|
48
|
+
|
package/index.js
CHANGED
|
@@ -23,8 +23,8 @@ const defaultForbidden = [
|
|
|
23
23
|
'(?:memory|记忆|记忆点|总结)\\s*[:=]',
|
|
24
24
|
];
|
|
25
25
|
|
|
26
|
-
// 严格 <output><message>...
|
|
27
|
-
// 1~5
|
|
26
|
+
// 严格 <output><message>... 结构:允许文�?/ <at>user_id</at> 文本 / <sticker>url</sticker>
|
|
27
|
+
// ������ 1~5 �� <message>��@ ֻ���ܴ����ֵ� user_id
|
|
28
28
|
const strictOutputPattern =
|
|
29
29
|
'^\\s*<output>\\s*(<message>(?:<at>\\d+<\\/at>\\s*)?(?:<sticker>[^<]*<\\/sticker>|[^<]*)<\\/message>\\s*){1,5}<\\/output>\\s*$';
|
|
30
30
|
|
|
@@ -220,32 +220,32 @@ function applyGuard(ctx, config) {
|
|
|
220
220
|
const strictMode = !!config.guardStrictOutputOnly;
|
|
221
221
|
const keywordMode = config.guardKeywordMode !== false;
|
|
222
222
|
const forbidden = compileMatchers(config.guardForbiddenPatterns, keywordMode);
|
|
223
|
-
const allowed = strictMode
|
|
224
|
-
? compileMatchers([config.guardStrictPattern || strictOutputPattern], false)
|
|
225
|
-
: compileMatchers(config.guardAllowedPatterns, keywordMode);
|
|
226
|
-
const original = Bot.prototype.sendMessage;
|
|
227
|
-
|
|
228
|
-
Bot.prototype.sendMessage = async function patched(channelId, content, referrer, options = {}) {
|
|
229
|
-
const ids = await original.call(this, channelId, content, referrer, options);
|
|
230
|
-
|
|
231
|
-
if (!shouldGuard(config, options)) {
|
|
232
|
-
return ids;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const text = extractText(content);
|
|
236
|
-
const reason = detectAbnormal(text, forbidden, allowed, strictMode);
|
|
237
|
-
|
|
238
|
-
if (!reason) {
|
|
239
|
-
return ids;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const preview = shorten(text, config.guardContentPreview);
|
|
243
|
-
if (config.guardLog) logger.warn(`[recall] ${reason} | content: ${preview}`);
|
|
244
|
-
const delay = Math.max(0, config.guardDelay) * 1000;
|
|
245
|
-
if (Array.isArray(ids) && ids.length && typeof this.deleteMessage === 'function') {
|
|
246
|
-
setTimeout(() => {
|
|
247
|
-
for (const id of ids) {
|
|
248
|
-
this.deleteMessage(channelId, id).catch((err) => {
|
|
223
|
+
const allowed = strictMode
|
|
224
|
+
? compileMatchers([config.guardStrictPattern || strictOutputPattern], false)
|
|
225
|
+
: compileMatchers(config.guardAllowedPatterns, keywordMode);
|
|
226
|
+
const original = Bot.prototype.sendMessage;
|
|
227
|
+
|
|
228
|
+
Bot.prototype.sendMessage = async function patched(channelId, content, referrer, options = {}) {
|
|
229
|
+
const ids = await original.call(this, channelId, content, referrer, options);
|
|
230
|
+
|
|
231
|
+
if (!shouldGuard(config, options)) {
|
|
232
|
+
return ids;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const text = extractText(content);
|
|
236
|
+
const reason = detectAbnormal(text, forbidden, allowed, strictMode);
|
|
237
|
+
|
|
238
|
+
if (!reason) {
|
|
239
|
+
return ids;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const preview = shorten(text, config.guardContentPreview);
|
|
243
|
+
if (config.guardLog) logger.warn(`[recall] ${reason} | content: ${preview}`);
|
|
244
|
+
const delay = Math.max(0, config.guardDelay) * 1000;
|
|
245
|
+
if (Array.isArray(ids) && ids.length && typeof this.deleteMessage === 'function') {
|
|
246
|
+
setTimeout(() => {
|
|
247
|
+
for (const id of ids) {
|
|
248
|
+
this.deleteMessage(channelId, id).catch((err) => {
|
|
249
249
|
logger.warn(`[recall-failed] id=${id} reason=${err?.message || err}`);
|
|
250
250
|
});
|
|
251
251
|
}
|
package/package.json
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "koishi-plugin-chatluna-think-viewer",
|
|
3
|
+
"version": "2.2.1",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"description": "通过命令/关键词查看 chatluna-character 最近一次回复的 \u003cthink\u003e 思考内容,并在消息格式异常时自动拦截/撤回。",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"koishi",
|
|
9
|
+
"chatluna",
|
|
10
|
+
"character",
|
|
11
|
+
"think",
|
|
12
|
+
"recall",
|
|
13
|
+
"guard",
|
|
14
|
+
"moderation"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/sCR0WN-s/koishi-plugin-chatluna-think-viewer",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/sCR0WN-s/koishi-plugin-chatluna-think-viewer.git"
|
|
20
|
+
},
|
|
21
|
+
"contributors": [
|
|
22
|
+
"sCR0WN-s \u003c2892511968@qq.com\u003e"
|
|
23
|
+
],
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"koishi": "^4.18.0",
|
|
26
|
+
"koishi-plugin-chatluna-character": "^0.0.180"
|
|
27
|
+
},
|
|
28
|
+
"koishi": {
|
|
29
|
+
"description": {
|
|
30
|
+
"zh": "通过命令/关键词查看 chatluna-character 最近一次回复的 \u003cthink\u003e 思考内容,并在消息格式异常时自动拦截/撤回。",
|
|
31
|
+
"en": "View \u003cthink\u003e blocks from chatluna-character and auto recall/guard malformed replies."
|
|
32
|
+
},
|
|
33
|
+
"service": {
|
|
34
|
+
"required": [
|
|
35
|
+
"chatluna_character"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"index.js",
|
|
41
|
+
"README.md"
|
|
42
|
+
]
|
|
43
|
+
}
|