koishi-plugin-hds-interlude 0.1.4-beta2 → 0.1.4-beta3
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/BEGINNER_GUIDE.md +1 -1
- package/CONFIGURATION_GUIDE.md +7 -1
- package/DEPLOYMENT_GUIDE.md +1 -1
- package/README.md +3 -3
- package/docs/CHANGELOG.md +7 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +151 -7
- package/lib/meta.d.ts +1 -1
- package/lib/narrator.d.ts +2 -2
- package/lib/qq-face.d.ts +4 -0
- package/lib/service.d.ts +7 -0
- package/package.json +3 -2
package/BEGINNER_GUIDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# HDS Interlude 新手引导
|
|
2
2
|
|
|
3
|
-
适用版本:`0.1.4-
|
|
3
|
+
适用版本:`0.1.4-beta3`
|
|
4
4
|
|
|
5
5
|
HDS Interlude 是 Koishi 的持续叙事聊天插件。插件使用共享主剧本保存角色状态、关系分支、已发生事件、待处理计划和长期记忆。用户消息会进入当前活动场景;主模型在同一次请求中续写已经发生的生活,并决定是否发送、延迟发送或暂不发送消息。实时写作读取一条按时间排序的活动场景记录:最近剧本文字、真实用户消息和已经成功投递的角色消息在同一条线上。剧本引子、场景外近期事实和长期记忆负责更早的历史。
|
|
6
6
|
|
package/CONFIGURATION_GUIDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# HDS Interlude 配置指南
|
|
2
2
|
|
|
3
|
-
适用版本:`0.1.4-
|
|
3
|
+
适用版本:`0.1.4-beta3`
|
|
4
4
|
|
|
5
5
|
第一次安装先看 `BEGINNER_GUIDE.md`。本文件严格按照 Koishi Console 的显示顺序说明当前字段;旧版本已经移除或隐藏的字段集中列在末尾,不再混入正常配置流程。
|
|
6
6
|
|
|
@@ -167,6 +167,12 @@ Embedding 地址留空时,插件会尝试从标准 `/chat/completions` 地址
|
|
|
167
167
|
|
|
168
168
|
转写成功后,主模型收到的用户事件会带有 `[用户语音转写]` 标记,并和当前文本、图片一起构成同一个回合。该功能需要 SnowLuma 支持原始 OneBot `fetch_ptt_text` 动作;NapCat 或其它实现不支持时会安全降级。它不把音频文件或 base64 写入 HDSI 数据库。
|
|
169
169
|
|
|
170
|
+
### 4.4 chatActions:QQ 原生表情
|
|
171
|
+
|
|
172
|
+
`nativeFaces` 控制是否允许结构化 QQ 原生小表情;关闭后主模型不会收到对应字段,插件也不会发送 face 段。
|
|
173
|
+
|
|
174
|
+
`expressionThreshold` 是表达严格度,不是固定发送频率。HDSI 会同时校验模型意愿与当前回复文字是否具有相同的非语言含义:低分或语义不相符时不投递。`0.70` 是平衡值;`0.90` 以上非常克制;`0.95` 及以上接近关闭,适合只保留纯文字聊天的场景。
|
|
175
|
+
|
|
170
176
|
## 5. sharedStory:共享剧本
|
|
171
177
|
|
|
172
178
|
当前运行时固定为“同一机器人账号一个活动主剧本”,因此不再显示旧版 `enabled` 开关。
|
package/DEPLOYMENT_GUIDE.md
CHANGED
|
@@ -45,7 +45,7 @@ Koishi 第一次启动会准备运行环境,耐心等待即可。
|
|
|
45
45
|
|
|
46
46
|
```powershell
|
|
47
47
|
cd C:\Users\你的用户名\AppData\Roaming\Koishi\Desktop\data\instances\default
|
|
48
|
-
npm install C:\路径\koishi-plugin-hds-interlude-0.1.
|
|
48
|
+
npm install --save-exact C:\路径\koishi-plugin-hds-interlude-0.1.4-beta3.tgz
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
安装完成后回到 Koishi Console,添加或启用 `hds-interlude`。
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
HDS Interlude 是一个面向 Koishi 一对一与多参与者场景的持续叙事聊天框架。它让用户消息、角色的沉默、延迟回复、主动联系和自动推进,都成为同一段生活剧本中自然可见的部分,并由一次主叙事写作连贯地决定。
|
|
6
6
|
|
|
7
|
-
当前版本:`0.1.4-
|
|
7
|
+
当前版本:`0.1.4-beta3`(测试版)。提供持续生活剧本、结构化投递、群聊意愿、多提供商模型连接与可选聊天动作。
|
|
8
8
|
|
|
9
9
|
## 文档导航
|
|
10
10
|
|
|
@@ -259,13 +259,13 @@ npm install koishi-plugin-hds-interlude@beta
|
|
|
259
259
|
使用本地预发布包时,可在 Koishi 实例目录执行:
|
|
260
260
|
|
|
261
261
|
```bash
|
|
262
|
-
npm install /absolute/path/to/koishi-plugin-hds-interlude-0.1.4-
|
|
262
|
+
npm install /absolute/path/to/koishi-plugin-hds-interlude-0.1.4-beta3.tgz
|
|
263
263
|
```
|
|
264
264
|
|
|
265
265
|
Windows 示例:
|
|
266
266
|
|
|
267
267
|
```powershell
|
|
268
|
-
npm install C:\dev\HDS-Interlude\plugins\hds-interlude\release\koishi-plugin-hds-interlude-0.1.4-
|
|
268
|
+
npm install C:\dev\HDS-Interlude\plugins\hds-interlude\release\koishi-plugin-hds-interlude-0.1.4-beta3.tgz
|
|
269
269
|
```
|
|
270
270
|
|
|
271
271
|
安装后重新加载 Koishi,再在 Console 启用插件。
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# 版本记录
|
|
2
2
|
|
|
3
|
+
## 0.1.4-beta3
|
|
4
|
+
|
|
5
|
+
- 入站 QQ 原生表情现在会在私聊、群聊与引用内容中翻译为稳定语义文字;经典系统表情复用 QFace 表,并补齐当前具名新增表情。未知未来 ID 保留“名称未收录”标记,不再交由模型猜测。
|
|
6
|
+
- QQ 原生小表情的 `expressionThreshold` 改为语义校准阈值:模型声明的意愿必须与当前回复文字相符才能投递,不能再用 `willingness: 1.0` 穿透高阈值;`0.95` 以上为接近关闭档。
|
|
7
|
+
- 收束原生表情提示词:日常回复不应附带表情,`nativeFace` 是可省略的表达动作,不是发送许可字段。
|
|
8
|
+
- 部署与配置文档同步 beta3 本地包路径,并说明原生表情开关和阈值含义。
|
|
9
|
+
|
|
3
10
|
## 0.1.4-beta2
|
|
4
11
|
|
|
5
12
|
- 优化聊天动作提示:私聊仅启用原生表情时不再注入群消息引用说明,减少无关上下文。
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
7
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
8
|
var __export = (target, all) => {
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
@@ -30,6 +40,7 @@ __export(src_exports, {
|
|
|
30
40
|
ZHIPU_FIRST_VISIBLE_TOKEN_TIMEOUT: () => ZHIPU_FIRST_VISIBLE_TOKEN_TIMEOUT,
|
|
31
41
|
ZHIPU_OFFICIAL_CHAT_ENDPOINT: () => ZHIPU_OFFICIAL_CHAT_ENDPOINT,
|
|
32
42
|
apply: () => apply,
|
|
43
|
+
calibratedNativeFaceWillingness: () => calibratedNativeFaceWillingness,
|
|
33
44
|
configuredProviders: () => configuredProviders,
|
|
34
45
|
createCompactor: () => createCompactor,
|
|
35
46
|
createEmbedder: () => createEmbedder,
|
|
@@ -1045,7 +1056,7 @@ function chatActionInstruction(capabilities) {
|
|
|
1045
1056
|
instructions.push(`The protagonist may add at most one lightweight message reaction without sending text: "messageReactions":[{"messageRef":"msg-...","reaction":"${capabilities.reactions.join("|")}"}]. Keep groupReply explicit, using mode=none when reacting without text.`);
|
|
1046
1057
|
}
|
|
1047
1058
|
if (capabilities.nativeFaces?.length) {
|
|
1048
|
-
instructions.push(`For a subtle native QQ face, return nativeFace: {"semantic":"${capabilities.nativeFaces.join("|")}","willingness":0.0-1.0}. Use it only when
|
|
1059
|
+
instructions.push(`For a subtle native QQ face, return nativeFace: {"semantic":"${capabilities.nativeFaces.join("|")}","willingness":0.0-1.0}. Omit nativeFace for routine wording: it is not a permission field and never needs to accompany a reply. Use it only when the reply text itself clearly carries the same nonverbal meaning; do not raise willingness to 1.0 to force a send. It is calibrated against reply text and is sent only when it reaches ${capabilities.expressionThreshold ?? 0.7}; at thresholds above 0.90, omit the field unless an expression is truly indispensable. Do not write bracketed face labels in reply text.`);
|
|
1049
1060
|
}
|
|
1050
1061
|
return instructions.join("\n");
|
|
1051
1062
|
}
|
|
@@ -1766,7 +1777,7 @@ function isRecord2(value) {
|
|
|
1766
1777
|
__name(isRecord2, "isRecord");
|
|
1767
1778
|
|
|
1768
1779
|
// src/meta.ts
|
|
1769
|
-
var HDS_INTERLUDE_VERSION = "0.1.4-
|
|
1780
|
+
var HDS_INTERLUDE_VERSION = "0.1.4-beta3";
|
|
1770
1781
|
|
|
1771
1782
|
// src/logging.ts
|
|
1772
1783
|
var import_node_util = require("node:util");
|
|
@@ -2052,6 +2063,118 @@ function clamp3(value, min, max) {
|
|
|
2052
2063
|
}
|
|
2053
2064
|
__name(clamp3, "clamp");
|
|
2054
2065
|
|
|
2066
|
+
// src/qq-face.ts
|
|
2067
|
+
var qface = __toESM(require("qface"));
|
|
2068
|
+
var QQ_NATIVE_FACE_NAME_EXTENSIONS = {
|
|
2069
|
+
349: "坚强",
|
|
2070
|
+
350: "贴贴",
|
|
2071
|
+
351: "敲敲",
|
|
2072
|
+
352: "咦",
|
|
2073
|
+
353: "拜托",
|
|
2074
|
+
354: "尊嘟假嘟",
|
|
2075
|
+
355: "耶",
|
|
2076
|
+
356: "666",
|
|
2077
|
+
357: "裂开",
|
|
2078
|
+
358: "骰子",
|
|
2079
|
+
359: "包剪锤",
|
|
2080
|
+
360: "亲亲",
|
|
2081
|
+
361: "狗狗笑哭",
|
|
2082
|
+
362: "好兄弟",
|
|
2083
|
+
363: "狗狗可怜",
|
|
2084
|
+
364: "超级赞",
|
|
2085
|
+
365: "狗狗生气",
|
|
2086
|
+
366: "芒狗",
|
|
2087
|
+
367: "狗狗疑问",
|
|
2088
|
+
368: "奥特笑哭",
|
|
2089
|
+
369: "彩虹",
|
|
2090
|
+
370: "祝贺",
|
|
2091
|
+
371: "冒泡",
|
|
2092
|
+
372: "气呼呼",
|
|
2093
|
+
373: "忙",
|
|
2094
|
+
374: "波波流泪",
|
|
2095
|
+
375: "超级鼓掌",
|
|
2096
|
+
376: "跺脚",
|
|
2097
|
+
377: "嗨",
|
|
2098
|
+
378: "企鹅笑哭",
|
|
2099
|
+
379: "企鹅流泪",
|
|
2100
|
+
380: "真棒",
|
|
2101
|
+
381: "路过",
|
|
2102
|
+
382: "emo",
|
|
2103
|
+
383: "企鹅爱心",
|
|
2104
|
+
384: "晚安",
|
|
2105
|
+
385: "太气了",
|
|
2106
|
+
386: "呜呜呜",
|
|
2107
|
+
387: "太好笑",
|
|
2108
|
+
388: "太头疼",
|
|
2109
|
+
389: "太赞了",
|
|
2110
|
+
390: "太头秃",
|
|
2111
|
+
391: "太沧桑",
|
|
2112
|
+
392: "龙年快乐",
|
|
2113
|
+
393: "新年中龙",
|
|
2114
|
+
394: "新年大龙",
|
|
2115
|
+
395: "略略略",
|
|
2116
|
+
396: "狼狗",
|
|
2117
|
+
397: "抛媚眼",
|
|
2118
|
+
398: "超级ok",
|
|
2119
|
+
399: "tui",
|
|
2120
|
+
400: "快乐",
|
|
2121
|
+
401: "超级转圈",
|
|
2122
|
+
402: "别说话",
|
|
2123
|
+
403: "出去玩",
|
|
2124
|
+
404: "闪亮登场",
|
|
2125
|
+
405: "好运来",
|
|
2126
|
+
406: "姐是女王",
|
|
2127
|
+
407: "我听听",
|
|
2128
|
+
408: "臭美",
|
|
2129
|
+
409: "送你花花",
|
|
2130
|
+
410: "么么哒",
|
|
2131
|
+
411: "一起嗨",
|
|
2132
|
+
412: "开心",
|
|
2133
|
+
413: "摇起来",
|
|
2134
|
+
415: "划龙舟",
|
|
2135
|
+
416: "中龙舟",
|
|
2136
|
+
417: "大龙舟",
|
|
2137
|
+
419: "火车",
|
|
2138
|
+
420: "中火车",
|
|
2139
|
+
421: "大火车",
|
|
2140
|
+
424: "续标识",
|
|
2141
|
+
425: "求放过",
|
|
2142
|
+
426: "玩火",
|
|
2143
|
+
427: "偷感",
|
|
2144
|
+
428: "收到",
|
|
2145
|
+
429: "蛇年快乐",
|
|
2146
|
+
430: "蛇身",
|
|
2147
|
+
431: "蛇尾"
|
|
2148
|
+
};
|
|
2149
|
+
function attributeValue(attributes, key) {
|
|
2150
|
+
const match = new RegExp(`(?:^|[\\s,])${key}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, "i").exec(attributes);
|
|
2151
|
+
return (match?.[1] ?? match?.[2] ?? match?.[3] ?? "").trim();
|
|
2152
|
+
}
|
|
2153
|
+
__name(attributeValue, "attributeValue");
|
|
2154
|
+
function qqNativeFaceName(id) {
|
|
2155
|
+
const key = String(id ?? "").trim();
|
|
2156
|
+
if (!key) return void 0;
|
|
2157
|
+
const extension = QQ_NATIVE_FACE_NAME_EXTENSIONS[key];
|
|
2158
|
+
if (extension) return extension;
|
|
2159
|
+
const face = qface.get(key);
|
|
2160
|
+
return face?.QDes?.replace(/^\//, "").trim() || void 0;
|
|
2161
|
+
}
|
|
2162
|
+
__name(qqNativeFaceName, "qqNativeFaceName");
|
|
2163
|
+
function describeQQNativeFace(id) {
|
|
2164
|
+
const key = String(id ?? "").trim();
|
|
2165
|
+
if (!key) return "[QQ 原生表情(未提供 ID)]";
|
|
2166
|
+
const name2 = qqNativeFaceName(key);
|
|
2167
|
+
return name2 ? `[QQ 原生表情:${name2}(ID: ${key})]` : `[QQ 原生表情(ID: ${key};名称未收录)]`;
|
|
2168
|
+
}
|
|
2169
|
+
__name(describeQQNativeFace, "describeQQNativeFace");
|
|
2170
|
+
function normalizeQQNativeFaceSegments(content) {
|
|
2171
|
+
return String(content ?? "").replace(/<face\b([^>]*)>(?:<\/face>)?/gi, (_match, attributes) => describeQQNativeFace(attributeValue(attributes, "id"))).replace(/\[CQ:face,([^\]]*)\]/gi, (_match, attributes) => describeQQNativeFace(attributeValue(attributes, "id"))).replace(/<mface\b([^>]*)>(?:<\/mface>)?/gi, (_match, attributes) => {
|
|
2172
|
+
const name2 = attributeValue(attributes, "summary") || attributeValue(attributes, "name");
|
|
2173
|
+
return name2 ? `[QQ 商城表情:${name2}]` : "[QQ 商城表情]";
|
|
2174
|
+
});
|
|
2175
|
+
}
|
|
2176
|
+
__name(normalizeQQNativeFaceSegments, "normalizeQQNativeFaceSegments");
|
|
2177
|
+
|
|
2055
2178
|
// src/types.ts
|
|
2056
2179
|
var emptyStorySetting = /* @__PURE__ */ __name(() => ({
|
|
2057
2180
|
character: { name: "Unnamed character", profile: "" },
|
|
@@ -2747,12 +2870,13 @@ var InterludeService = class extends import_koishi.Service {
|
|
|
2747
2870
|
const senderId = normalizeAccountId(session.userId);
|
|
2748
2871
|
const senderName = await this.groupSenderName(groupId, senderId, session);
|
|
2749
2872
|
const quote = describeQuotedMessage(session, story.setting.character.name);
|
|
2873
|
+
const messageContent = normalizeQQNativeFaceSegments(session.content);
|
|
2750
2874
|
const accepted = await this.serial(story.id, async () => {
|
|
2751
2875
|
const current = await this.getStory(story.id);
|
|
2752
2876
|
const entry = await this.appendEntry(current.id, {
|
|
2753
2877
|
kind: "group-message",
|
|
2754
2878
|
actor: "user",
|
|
2755
|
-
content:
|
|
2879
|
+
content: messageContent,
|
|
2756
2880
|
occurredAt: now.toISOString(),
|
|
2757
2881
|
metadata: {
|
|
2758
2882
|
groupId,
|
|
@@ -2773,7 +2897,7 @@ var InterludeService = class extends import_koishi.Service {
|
|
|
2773
2897
|
speaker: formatGroupSpeaker(senderName, senderId),
|
|
2774
2898
|
...messageId ? { messageId, messageRef: groupMessageRef(accepted.id) } : {},
|
|
2775
2899
|
...quote ? { quote } : {},
|
|
2776
|
-
content:
|
|
2900
|
+
content: messageContent,
|
|
2777
2901
|
occurredAt: now,
|
|
2778
2902
|
direction: "user"
|
|
2779
2903
|
}, mentionedBot, quotedBot);
|
|
@@ -3098,7 +3222,8 @@ ${message.content}`).join("\n\n");
|
|
|
3098
3222
|
const allowed = new Set(capabilities?.nativeFaces ?? []);
|
|
3099
3223
|
if (!allowed.size) return void 0;
|
|
3100
3224
|
const draft = decision.nativeFace;
|
|
3101
|
-
|
|
3225
|
+
const replyContent = decision.groupReply?.content ?? decision.interaction?.reply?.content ?? "";
|
|
3226
|
+
if (draft && allowed.has(draft.semantic) && calibratedNativeFaceWillingness(draft.semantic, draft.willingness, replyContent) >= (capabilities?.expressionThreshold ?? this.expressionThreshold)) {
|
|
3102
3227
|
return draft.semantic;
|
|
3103
3228
|
}
|
|
3104
3229
|
return void 0;
|
|
@@ -3336,7 +3461,7 @@ ${message.content}`).join("\n\n");
|
|
|
3336
3461
|
describeVisionEvent(session) {
|
|
3337
3462
|
const raw = String(session.content ?? "");
|
|
3338
3463
|
const sources = extractSessionImageSources(session);
|
|
3339
|
-
const text2 = raw.replace(/<\/?(?:img|image|audio|record)\b[^>]*>/gi, "").replace(/\[CQ:(?:image|record),[^\]]*\]/gi, "").trim();
|
|
3464
|
+
const text2 = normalizeQQNativeFaceSegments(raw).replace(/<\/?(?:img|image|audio|record)\b[^>]*>/gi, "").replace(/\[CQ:(?:image|record),[^\]]*\]/gi, "").trim();
|
|
3340
3465
|
const content = text2;
|
|
3341
3466
|
return { content, sources };
|
|
3342
3467
|
}
|
|
@@ -6268,6 +6393,24 @@ function normalizeExpressionThreshold(value) {
|
|
|
6268
6393
|
return Number.isFinite(number) ? Math.max(0, Math.min(1, number)) : 0.7;
|
|
6269
6394
|
}
|
|
6270
6395
|
__name(normalizeExpressionThreshold, "normalizeExpressionThreshold");
|
|
6396
|
+
function calibratedNativeFaceWillingness(semantic, willingness, replyContent) {
|
|
6397
|
+
const text2 = String(replyContent ?? "").replace(/<sep\/>/g, " ").trim();
|
|
6398
|
+
if (!text2) return 0;
|
|
6399
|
+
const patterns = {
|
|
6400
|
+
smile: /(?:微笑|开心|高兴|谢谢|好耶|好呀|可以|行吧|嘿|哈哈)/i,
|
|
6401
|
+
laugh: /(?:哈{2,}|笑死|好笑|乐|绷不住|蚌埠|草|救命)/i,
|
|
6402
|
+
sweat: /(?:流汗|尴尬|无语|服了|麻了|救命|离谱|完了|累|忙|不知道怎么说)/i,
|
|
6403
|
+
awkward: /(?:尴尬|那个|呃|emm|……|\.{3,}|我真的|怎么说呢)/i,
|
|
6404
|
+
heart: /(?:喜欢|爱你|抱抱|可爱|谢谢|好耶|开心|高兴)/i,
|
|
6405
|
+
surprised: /(?:不会吧|真的假的|居然|什么|怎么会|\?{1,}|?{1,}|!{1,}|!{1,})/i,
|
|
6406
|
+
sad: /(?:难过|哭|委屈|可怜|遗憾|心疼|唉)/i,
|
|
6407
|
+
angry: /(?:生气|气死|烦|闭嘴|别[再乱闹说]|离谱|过分|你.*(?:啊|吧|?|!|!))/i
|
|
6408
|
+
};
|
|
6409
|
+
const semanticMatch = patterns[semantic].test(text2);
|
|
6410
|
+
const evidence = semanticMatch ? 0.9 : 0.2;
|
|
6411
|
+
return Math.min(0.9, normalizeExpressionThreshold(willingness) * (0.25 + evidence * 0.75));
|
|
6412
|
+
}
|
|
6413
|
+
__name(calibratedNativeFaceWillingness, "calibratedNativeFaceWillingness");
|
|
6271
6414
|
function targetableMessageId(value) {
|
|
6272
6415
|
const id = String(value ?? "").trim();
|
|
6273
6416
|
return /^-?\d+$/.test(id) && id !== "0" ? id : void 0;
|
|
@@ -6318,7 +6461,7 @@ function describeQuotedMessage(session, characterName = "主角") {
|
|
|
6318
6461
|
}
|
|
6319
6462
|
__name(describeQuotedMessage, "describeQuotedMessage");
|
|
6320
6463
|
function normalizeQuotedMessageContent(value) {
|
|
6321
|
-
const raw =
|
|
6464
|
+
const raw = normalizeQQNativeFaceSegments(value);
|
|
6322
6465
|
const content = raw.replace(/<(?:img|image)\b[^>]*\/?>(?:<\/(?:img|image)>)?/gi, "[图片]").replace(/<(?:audio|record)\b[^>]*\/?>(?:<\/(?:audio|record)>)?/gi, "[语音]").replace(/<video\b[^>]*\/?>(?:<\/video>)?/gi, "[视频]").replace(/<(?:face|mface)\b[^>]*\/?>(?:<\/(?:face|mface)>)?/gi, "[表情]").replace(/<at\b[^>]*(?:name|id)=["']?([^\s"'>]+)[^>]*\/?>(?:<\/at>)?/gi, "[@$1]").replace(/\[CQ:image,[^\]]*\]/gi, "[图片]").replace(/\[CQ:record,[^\]]*\]/gi, "[语音]").replace(/\[CQ:video,[^\]]*\]/gi, "[视频]").replace(/\[CQ:face,[^\]]*\]/gi, "[表情]").replace(/<[^>]+>/g, "").replace(/[\r\n]+/g, " ").replace(/\s{2,}/g, " ").trim();
|
|
6323
6466
|
return clip(content, 1500);
|
|
6324
6467
|
}
|
|
@@ -7855,6 +7998,7 @@ __name(looksLikeInterludeCommand, "looksLikeInterludeCommand");
|
|
|
7855
7998
|
ZHIPU_FIRST_VISIBLE_TOKEN_TIMEOUT,
|
|
7856
7999
|
ZHIPU_OFFICIAL_CHAT_ENDPOINT,
|
|
7857
8000
|
apply,
|
|
8001
|
+
calibratedNativeFaceWillingness,
|
|
7858
8002
|
configuredProviders,
|
|
7859
8003
|
createCompactor,
|
|
7860
8004
|
createEmbedder,
|
package/lib/meta.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const HDS_INTERLUDE_VERSION = "0.1.4-
|
|
1
|
+
export declare const HDS_INTERLUDE_VERSION = "0.1.4-beta3";
|
package/lib/narrator.d.ts
CHANGED
|
@@ -230,7 +230,7 @@ export declare function toPromptPayload(request: NarrativeRequest): {
|
|
|
230
230
|
}[];
|
|
231
231
|
durableFacts: {
|
|
232
232
|
participantId: string;
|
|
233
|
-
scope: "
|
|
233
|
+
scope: "character" | "world" | "relationship" | "event" | "promise";
|
|
234
234
|
content: string;
|
|
235
235
|
importance: number;
|
|
236
236
|
confidence: number;
|
|
@@ -378,7 +378,7 @@ export declare function toPromptPayload(request: NarrativeRequest): {
|
|
|
378
378
|
groupContext: {
|
|
379
379
|
messages: {
|
|
380
380
|
occurredAt: string;
|
|
381
|
-
direction: "
|
|
381
|
+
direction: "user" | "character";
|
|
382
382
|
quote?: import("./types").QuotedMessageContext;
|
|
383
383
|
senderId: string;
|
|
384
384
|
senderName: string;
|
package/lib/qq-face.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function qqNativeFaceName(id: unknown): string;
|
|
2
|
+
export declare function describeQQNativeFace(id: unknown): string;
|
|
3
|
+
/** Convert adapter markup into stable narrator-visible meaning without asking a model to infer an icon. */
|
|
4
|
+
export declare function normalizeQQNativeFaceSegments(content: unknown): string;
|
package/lib/service.d.ts
CHANGED
|
@@ -687,6 +687,13 @@ export declare function extractSessionVoiceCount(session: Pick<Session, 'content
|
|
|
687
687
|
/** Voice and typed text share one user event. The explicit marker lets the
|
|
688
688
|
* narrator distinguish recognized speech from ordinary typed text. */
|
|
689
689
|
export declare function mergeUserMessageWithVoiceTranscripts(text: string, transcripts: string[], detected?: number): string;
|
|
690
|
+
/**
|
|
691
|
+
* A model's willingness is an intent estimate, not a transport permission.
|
|
692
|
+
* Native faces need a visible-text counterpart so a model cannot turn every
|
|
693
|
+
* routine reply into a face merely by returning willingness=1. The 0.90 cap
|
|
694
|
+
* deliberately makes thresholds above 0.90 an effective near-disable mode.
|
|
695
|
+
*/
|
|
696
|
+
export declare function calibratedNativeFaceWillingness(semantic: NativeFaceSemantic, willingness: unknown, replyContent: unknown): number;
|
|
690
697
|
export declare function describeQuotedMessage(session: Session, characterName?: string): QuotedMessageContext | undefined;
|
|
691
698
|
export declare function normalizeQuotedMessageContent(value: unknown): string;
|
|
692
699
|
export declare function normalizeAllowedReactions(value: unknown): ChatReactionName[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-hds-interlude",
|
|
3
|
-
"version": "0.1.4-
|
|
3
|
+
"version": "0.1.4-beta3",
|
|
4
4
|
"description": "A time-aware, persistent narrative chat framework for Koishi.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"koishi": {"service": {"optional": ["puppeteer"]}},
|
|
15
15
|
"peerDependencies": {"koishi": "^4.18.7", "koishi-plugin-puppeteer": "^3.9.0"},
|
|
16
16
|
"peerDependenciesMeta": {"koishi-plugin-puppeteer": {"optional": true}},
|
|
17
|
-
"devDependencies": {"koishi-plugin-puppeteer": "^3.9.0"}
|
|
17
|
+
"devDependencies": {"koishi-plugin-puppeteer": "^3.9.0"},
|
|
18
|
+
"dependencies": {"qface": "^1.4.1"}
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
|