@jeik/dingtalk-connector 0.8.21-fix8 → 0.8.21-fix9
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/dist/entry-bundled.mjs +1 -1
- package/dist/{gateway-methods-D7aACzCW.mjs → gateway-methods-B9kuAOFf.mjs} +1 -1
- package/dist/{gateway-methods-DM8lWI4F.mjs → gateway-methods-DfW2oZ6c.mjs} +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{message-handler-BSpEBVN0.mjs → message-handler-CWW2dKz0.mjs} +8 -10
- package/dist/{messaging-CBQl0D00.mjs → messaging-CvZBBMgv.mjs} +28 -27
- package/dist/{runtime-vdFNy2P8.mjs → runtime-CUSz0JLV.mjs} +2 -2
- package/package.json +1 -1
- package/src/reply-dispatcher.ts +14 -20
- package/src/services/reply-markers.ts +63 -65
package/dist/entry-bundled.mjs
CHANGED
|
@@ -23,7 +23,7 @@ var entry_bundled_default = defineBundledChannelEntry({
|
|
|
23
23
|
exportName: "setDingtalkRuntime"
|
|
24
24
|
},
|
|
25
25
|
async registerFull(api) {
|
|
26
|
-
const { registerGatewayMethods } = await import("./gateway-methods-
|
|
26
|
+
const { registerGatewayMethods } = await import("./gateway-methods-B9kuAOFf.mjs");
|
|
27
27
|
registerGatewayMethods(api);
|
|
28
28
|
}
|
|
29
29
|
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as registerGatewayMethods } from "./gateway-methods-
|
|
1
|
+
import { t as registerGatewayMethods } from "./gateway-methods-DfW2oZ6c.mjs";
|
|
2
2
|
export { registerGatewayMethods };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as resolveDingtalkAccount, t as listDingtalkAccountIds } from "./accounts-BAzdqkAV.mjs";
|
|
2
2
|
import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
|
|
3
3
|
import { r as getAccessToken, t as DINGTALK_API } from "./utils-CIfI_3Jh.mjs";
|
|
4
|
-
import { c as prepareMultiBotMentions, i as sendProactive, s as buildBotMentionTable, u as finishAICard } from "./messaging-
|
|
4
|
+
import { c as prepareMultiBotMentions, i as sendProactive, s as buildBotMentionTable, u as finishAICard } from "./messaging-CvZBBMgv.mjs";
|
|
5
5
|
import { c as getUnionId, d as recallEmotionReply } from "./utils-legacy-CALCPP1t.mjs";
|
|
6
6
|
//#region src/docs.ts
|
|
7
7
|
var DingtalkDocsClient = class {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as initDingtalkPluginConfigSchema, i as dingtalkPlugin, n as setDingtalkRuntime } from "./runtime-
|
|
2
|
-
import { t as registerGatewayMethods } from "./gateway-methods-
|
|
1
|
+
import { a as initDingtalkPluginConfigSchema, i as dingtalkPlugin, n as setDingtalkRuntime } from "./runtime-CUSz0JLV.mjs";
|
|
2
|
+
import { t as registerGatewayMethods } from "./gateway-methods-DfW2oZ6c.mjs";
|
|
3
3
|
//#region index.ts
|
|
4
4
|
/**
|
|
5
5
|
* 检测同一 plugin id 在多个路径被加载的情况。
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { u as uploadMediaToDingTalk } from "./media-cz72EVS3.mjs";
|
|
2
2
|
import { a as resolveDingtalkAccount } from "./accounts-BAzdqkAV.mjs";
|
|
3
|
-
import { r as CHANNEL_ID, t as getDingtalkRuntime } from "./runtime-
|
|
3
|
+
import { r as CHANNEL_ID, t as getDingtalkRuntime } from "./runtime-CUSz0JLV.mjs";
|
|
4
4
|
import { n as createLoggerFromConfig } from "./logger-mZ9OSbmD.mjs";
|
|
5
5
|
import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
|
|
6
6
|
import { i as getOapiAccessToken } from "./utils-CIfI_3Jh.mjs";
|
|
7
|
-
import { _ as PROCESS_TAG, a as sendTextMessage, b as finalClean, f as isQpsLimitError, g as FINAL_TAG, h as unregisterActiveCard, i as sendProactive, l as createAICardForTarget, m as streamAICard, p as registerActiveCard, r as sendMessage, t as sendMarkdownMessage, u as finishAICard, v as displayClean, y as extractFinal } from "./messaging-
|
|
7
|
+
import { _ as PROCESS_TAG, a as sendTextMessage, b as finalClean, f as isQpsLimitError, g as FINAL_TAG, h as unregisterActiveCard, i as sendProactive, l as createAICardForTarget, m as streamAICard, p as registerActiveCard, r as sendMessage, t as sendMarkdownMessage, u as finishAICard, v as displayClean, y as extractFinal } from "./messaging-CvZBBMgv.mjs";
|
|
8
8
|
import { a as QUEUE_BUSY_ACK_PHRASES, n as normalizeSlashCommand, t as buildSessionContext } from "./session-DJ4jYqPv.mjs";
|
|
9
9
|
import { d as recallEmotionReply, o as getAccessToken, r as addEmotionReply, s as getOapiAccessToken$1, t as DINGTALK_API } from "./utils-legacy-CALCPP1t.mjs";
|
|
10
10
|
import "./chunk-upload-BBQgGtcZ.mjs";
|
|
@@ -233,22 +233,20 @@ function createDingtalkReplyDispatcher(params) {
|
|
|
233
233
|
const observeReply = (raw, isReasoning) => {
|
|
234
234
|
const text = raw ?? "";
|
|
235
235
|
if (!text) return;
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
const abnormal = headTag !== null && tailTag !== null && headTag !== tailTag;
|
|
239
|
-
if (!abnormal && (headTag === "final" || tailTag === "final")) {
|
|
236
|
+
const fin = extractFinal(text);
|
|
237
|
+
if (fin !== null) {
|
|
240
238
|
if (!finalMarkerLogged) {
|
|
241
239
|
finalMarkerLogged = true;
|
|
242
|
-
log.info(`[DingTalk][marker]
|
|
240
|
+
log.info(`[DingTalk][marker] 检测到 ${FINAL_TAG},最终答案取最后一个 ${PROCESS_TAG} 之后内容,跳过 OpenClaw 兜底`);
|
|
243
241
|
}
|
|
244
|
-
finalMarkedText =
|
|
242
|
+
finalMarkedText = fin;
|
|
245
243
|
markerSystemActive = true;
|
|
246
244
|
return;
|
|
247
245
|
}
|
|
248
|
-
if (
|
|
246
|
+
if (text.includes("[-process-]")) {
|
|
249
247
|
if (!processMarkerLogged) {
|
|
250
248
|
processMarkerLogged = true;
|
|
251
|
-
log.info(`[DingTalk][marker]
|
|
249
|
+
log.info(`[DingTalk][marker] 检测到 ${PROCESS_TAG}(过程段),抑制 OpenClaw 默认兜底`);
|
|
252
250
|
}
|
|
253
251
|
markerSystemActive = true;
|
|
254
252
|
return;
|
|
@@ -7,43 +7,44 @@ import { r as MEDIA_MSG_TYPES } from "./session-DJ4jYqPv.mjs";
|
|
|
7
7
|
const PROCESS_TAG = "[-process-]";
|
|
8
8
|
const FINAL_TAG = "[-final-]";
|
|
9
9
|
const EDGE_WS = /^[ \t\r\n]+|[ \t\r\n]+$/g;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const HR_LINE = /^[ \t]*(?:[-*_][ \t]*){3,}(?:\r?\n|$)/;
|
|
11
|
+
/** 剥掉文本中所有 [-process-] / [-final-] 标记(含中间的),首尾空白清掉。 */
|
|
12
|
+
function stripAllMarkers(text) {
|
|
13
|
+
if (!text) return "";
|
|
14
|
+
return text.split(PROCESS_TAG).join("").split(FINAL_TAG).join("").replace(EDGE_WS, "");
|
|
15
|
+
}
|
|
16
|
+
/** 清掉段落开头的空白行 + markdown 分割横线(反复剥,处理 "\n\n---\n" 这种)。 */
|
|
17
|
+
function stripLeadingSeparators(text) {
|
|
18
|
+
let s = text.replace(/^[ \t\r\n]+/, "");
|
|
19
|
+
let m;
|
|
20
|
+
while ((m = s.match(HR_LINE)) && m[0].length > 0) s = s.slice(m[0].length).replace(/^[ \t\r\n]+/, "");
|
|
21
|
+
return s;
|
|
22
|
+
}
|
|
23
|
+
/** 取最终答案:取「最后一个 [-process-] 右边、[-final-] 左边」那段,剥残留标记 + 开头分隔,首尾清白。
|
|
24
|
+
* 没有 [-final-] → null(不是最终答案,交给 OpenClaw 兜底)。 */
|
|
13
25
|
function extractFinal(text) {
|
|
14
26
|
if (!text) return null;
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
/** 剥掉开头和结尾的一个标记 token([-process-] 或 [-final-],头尾优先,中间的保留)。 */
|
|
25
|
-
function stripOneMarker(text) {
|
|
26
|
-
if (!text) return "";
|
|
27
|
-
let result = text;
|
|
28
|
-
if (result.startsWith("[-process-]")) result = result.slice(11);
|
|
29
|
-
else if (result.startsWith("[-final-]")) result = result.slice(9);
|
|
30
|
-
if (result.endsWith("[-process-]")) result = result.slice(0, -11);
|
|
31
|
-
else if (result.endsWith("[-final-]")) result = result.slice(0, -9);
|
|
32
|
-
return result.replace(EDGE_WS, "");
|
|
27
|
+
const fi = text.lastIndexOf(FINAL_TAG);
|
|
28
|
+
if (fi < 0) return null;
|
|
29
|
+
const before = text.slice(0, fi);
|
|
30
|
+
const pi = before.lastIndexOf(PROCESS_TAG);
|
|
31
|
+
let seg = pi >= 0 ? before.slice(pi + 11) : before;
|
|
32
|
+
seg = seg.split(PROCESS_TAG).join("").split(FINAL_TAG).join("");
|
|
33
|
+
seg = stripLeadingSeparators(seg).replace(EDGE_WS, "");
|
|
34
|
+
return seg || stripAllMarkers(text);
|
|
33
35
|
}
|
|
34
|
-
/** 去掉流式途中末尾未闭合的半截标记(如 "[-fin",缺右 "]"
|
|
36
|
+
/** 去掉流式途中末尾未闭合的半截标记(如 "[-fin",缺右 "]")。完整标记交给 stripAllMarkers。 */
|
|
35
37
|
function stripPartialTail(text) {
|
|
36
38
|
if (!text) return "";
|
|
37
39
|
return text.replace(/\[-[a-z]*-?$/i, "");
|
|
38
40
|
}
|
|
39
|
-
/**
|
|
41
|
+
/** 定稿/单条消息用:剥光所有标记,保留完整正文(message 工具单条消息走这里)。 */
|
|
40
42
|
function finalClean(text) {
|
|
41
|
-
return
|
|
43
|
+
return stripAllMarkers(text);
|
|
42
44
|
}
|
|
43
|
-
/**
|
|
45
|
+
/** 流式展示用:剥光所有标记 + 末尾半截标记。 */
|
|
44
46
|
function displayClean(text) {
|
|
45
|
-
|
|
46
|
-
return fin !== null ? fin : stripPartialTail(stripOneMarker(text));
|
|
47
|
+
return stripPartialTail(stripAllMarkers(text));
|
|
47
48
|
}
|
|
48
49
|
//#endregion
|
|
49
50
|
//#region src/services/messaging/card.ts
|
|
@@ -3,7 +3,7 @@ import { a as resolveDingtalkAccount, c as addWildcardAllowFrom, d as hasConfigu
|
|
|
3
3
|
import { t as createLogger } from "./logger-mZ9OSbmD.mjs";
|
|
4
4
|
import { t as dingtalkHttp } from "./http-client-DFWZgO1n.mjs";
|
|
5
5
|
import "./utils-CIfI_3Jh.mjs";
|
|
6
|
-
import { b as finalClean, d as getActiveCardForConversation, n as sendMediaToDingTalk, o as sendTextToDingTalk } from "./messaging-
|
|
6
|
+
import { b as finalClean, d as getActiveCardForConversation, n as sendMediaToDingTalk, o as sendTextToDingTalk } from "./messaging-CvZBBMgv.mjs";
|
|
7
7
|
import { createRequire } from "node:module";
|
|
8
8
|
import { z, z as z$1 } from "zod";
|
|
9
9
|
//#region src/secret-input.ts
|
|
@@ -919,7 +919,7 @@ async function monitorDingtalkProvider(opts = {}) {
|
|
|
919
919
|
const log = createLogger(cfg.channels?.["dingtalk-connector"]?.debug ?? false);
|
|
920
920
|
const [accountsModule, monitorAccountModule, monitorSingleModule] = await Promise.all([
|
|
921
921
|
import("./accounts-BQptOmgB.mjs"),
|
|
922
|
-
import("./message-handler-
|
|
922
|
+
import("./message-handler-CWW2dKz0.mjs"),
|
|
923
923
|
import("./connection-DHHFFNQJ.mjs")
|
|
924
924
|
]);
|
|
925
925
|
const { resolveDingtalkAccount, listEnabledDingtalkAccounts } = accountsModule;
|
package/package.json
CHANGED
package/src/reply-dispatcher.ts
CHANGED
|
@@ -116,50 +116,44 @@ export function createDingtalkReplyDispatcher(params: CreateDingtalkReplyDispatc
|
|
|
116
116
|
let finalMarkerLogged = false;
|
|
117
117
|
|
|
118
118
|
// 观察每段到达的文本,更新标记认定状态。
|
|
119
|
-
//
|
|
120
|
-
// [-final-]
|
|
121
|
-
//
|
|
122
|
-
// 无标记 / 头尾标记类型不同 → 走 OpenClaw 默认兜底
|
|
119
|
+
// 含 [-final-] → 最终答案 = 最后一个 [-process-] 右边、[-final-] 左边那段(extractFinal),跳过兜底
|
|
120
|
+
// 含 [-process-](无 [-final-])→ 过程段,激活标记系统抑制 OpenClaw 兜底
|
|
121
|
+
// 无标记 → 走 OpenClaw 默认兜底
|
|
123
122
|
let markerSystemActive = false;
|
|
124
123
|
|
|
125
124
|
const observeReply = (raw: string | undefined, isReasoning: boolean | undefined) => {
|
|
126
125
|
const text = raw ?? "";
|
|
127
126
|
if (!text) return;
|
|
128
127
|
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
const abnormal = headTag !== null && tailTag !== null && headTag !== tailTag;
|
|
133
|
-
|
|
134
|
-
// [-final-] 在头/尾(非异常)→ 标记系统激活,提取最终答案,跳过 OpenClaw 兜底
|
|
135
|
-
if (!abnormal && (headTag === "final" || tailTag === "final")) {
|
|
128
|
+
// [-final-] 出现 → 提取最终段(最后一个 [-process-] 之后),跳过 OpenClaw 兜底
|
|
129
|
+
const fin = extractFinal(text);
|
|
130
|
+
if (fin !== null) {
|
|
136
131
|
if (!finalMarkerLogged) {
|
|
137
132
|
finalMarkerLogged = true;
|
|
138
|
-
log.info(`[DingTalk][marker]
|
|
133
|
+
log.info(`[DingTalk][marker] 检测到 ${FINAL_TAG},最终答案取最后一个 ${PROCESS_TAG} 之后内容,跳过 OpenClaw 兜底`);
|
|
139
134
|
}
|
|
140
|
-
finalMarkedText =
|
|
135
|
+
finalMarkedText = fin;
|
|
141
136
|
markerSystemActive = true;
|
|
142
137
|
return;
|
|
143
138
|
}
|
|
144
139
|
|
|
145
|
-
// [-process-]
|
|
146
|
-
if (
|
|
140
|
+
// 只有 [-process-](无 [-final-])→ 过程段,激活标记系统抑制兜底
|
|
141
|
+
if (text.includes(PROCESS_TAG)) {
|
|
147
142
|
if (!processMarkerLogged) {
|
|
148
143
|
processMarkerLogged = true;
|
|
149
|
-
log.info(`[DingTalk][marker]
|
|
144
|
+
log.info(`[DingTalk][marker] 检测到 ${PROCESS_TAG}(过程段),抑制 OpenClaw 默认兜底`);
|
|
150
145
|
}
|
|
151
146
|
markerSystemActive = true;
|
|
152
147
|
return;
|
|
153
148
|
}
|
|
154
149
|
|
|
155
|
-
//
|
|
156
|
-
// 已激活则保持沉默,让标记系统独占最终答案判定
|
|
150
|
+
// 无标记:标记系统未激活时走 OpenClaw 兜底;已激活则沉默,让标记系统独占判定
|
|
157
151
|
if (!markerSystemActive && !isReasoning && text.trim()) lastAnswerText = text;
|
|
158
152
|
};
|
|
159
153
|
|
|
160
154
|
// 选定本轮最终答案:
|
|
161
|
-
// 标记系统激活 → finalMarkedText
|
|
162
|
-
//
|
|
155
|
+
// 标记系统激活 → finalMarkedText(最终段)优先,accumulatedText 流式兜底(跳过 OpenClaw)
|
|
156
|
+
// 未激活(无标记)→ lastAnswerText(OpenClaw isReasoning 兜底),accumulatedText 兜底
|
|
163
157
|
const pickFinalText = (): string =>
|
|
164
158
|
markerSystemActive ? (finalMarkedText ?? accumulatedText) : (lastAnswerText || accumulatedText);
|
|
165
159
|
|
|
@@ -1,65 +1,63 @@
|
|
|
1
|
-
// 回复标记工具 —— 配合 prompt-rewriter 插件注入的"打标记"指令使用。
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// 最终答案 =
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export const
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return fin !== null ? fin : stripPartialTail(stripOneMarker(text));
|
|
65
|
-
}
|
|
1
|
+
// 回复标记工具 —— 配合 prompt-rewriter 插件注入的"打标记"指令使用。
|
|
2
|
+
//
|
|
3
|
+
// 【段落方案】过程段末尾打 [-process-],最终段末尾打 [-final-]。agent 常把整轮写成一段:
|
|
4
|
+
// 过程1…[-process-] 过程2…[-process-] … 最终汇总…[-final-]
|
|
5
|
+
// 最终答案 = 「最后一个 [-process-] 右边、[-final-] 左边」那段(即最终汇总),剥掉残留标记,
|
|
6
|
+
// 并清掉该段开头的换行 / markdown 分割横线(---、***、___)。
|
|
7
|
+
// 没有 [-process-] 时 = [-final-] 左边的全部。没有 [-final-] → 不是最终答案。
|
|
8
|
+
//
|
|
9
|
+
// ⚠️ 标记字面量必须与 prompt-rewriter 的 rewriter.ts 保持一致(两处重复,改一处要同步另一处)。
|
|
10
|
+
|
|
11
|
+
export const PROCESS_TAG = "[-process-]";
|
|
12
|
+
export const FINAL_TAG = "[-final-]";
|
|
13
|
+
|
|
14
|
+
const EDGE_WS = /^[ \t\r\n]+|[ \t\r\n]+$/g;
|
|
15
|
+
// markdown 分割横线整行:3+ 个 - / * / _(其间可有空格),如 ---、***、- - -
|
|
16
|
+
const HR_LINE = /^[ \t]*(?:[-*_][ \t]*){3,}(?:\r?\n|$)/;
|
|
17
|
+
|
|
18
|
+
/** 剥掉文本中所有 [-process-] / [-final-] 标记(含中间的),首尾空白清掉。 */
|
|
19
|
+
export function stripAllMarkers(text: string | undefined | null): string {
|
|
20
|
+
if (!text) return "";
|
|
21
|
+
return text.split(PROCESS_TAG).join("").split(FINAL_TAG).join("").replace(EDGE_WS, "");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** 清掉段落开头的空白行 + markdown 分割横线(反复剥,处理 "\n\n---\n" 这种)。 */
|
|
25
|
+
function stripLeadingSeparators(text: string): string {
|
|
26
|
+
let s = text.replace(/^[ \t\r\n]+/, "");
|
|
27
|
+
let m: RegExpMatchArray | null;
|
|
28
|
+
while ((m = s.match(HR_LINE)) && m[0].length > 0) {
|
|
29
|
+
s = s.slice(m[0].length).replace(/^[ \t\r\n]+/, "");
|
|
30
|
+
}
|
|
31
|
+
return s;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 取最终答案:取「最后一个 [-process-] 右边、[-final-] 左边」那段,剥残留标记 + 开头分隔,首尾清白。
|
|
35
|
+
* 没有 [-final-] → null(不是最终答案,交给 OpenClaw 兜底)。 */
|
|
36
|
+
export function extractFinal(text: string | undefined | null): string | null {
|
|
37
|
+
if (!text) return null;
|
|
38
|
+
const fi = text.lastIndexOf(FINAL_TAG); // [-final-] = 最终段右边界
|
|
39
|
+
if (fi < 0) return null;
|
|
40
|
+
const before = text.slice(0, fi);
|
|
41
|
+
const pi = before.lastIndexOf(PROCESS_TAG); // 最后一个 [-process-] = 最终段左边界
|
|
42
|
+
let seg = pi >= 0 ? before.slice(pi + PROCESS_TAG.length) : before;
|
|
43
|
+
seg = seg.split(PROCESS_TAG).join("").split(FINAL_TAG).join(""); // 残留标记保险
|
|
44
|
+
seg = stripLeadingSeparators(seg).replace(EDGE_WS, "");
|
|
45
|
+
// 段为空(如 [-final-] 在最前)→ 退回剥光全文,避免空答案
|
|
46
|
+
return seg || stripAllMarkers(text);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 去掉流式途中末尾未闭合的半截标记(如 "[-fin",缺右 "]")。完整标记交给 stripAllMarkers。 */
|
|
50
|
+
export function stripPartialTail(text: string | undefined | null): string {
|
|
51
|
+
if (!text) return "";
|
|
52
|
+
return text.replace(/\[-[a-z]*-?$/i, "");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** 定稿/单条消息用:剥光所有标记,保留完整正文(message 工具单条消息走这里)。 */
|
|
56
|
+
export function finalClean(text: string | undefined | null): string {
|
|
57
|
+
return stripAllMarkers(text);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 流式展示用:剥光所有标记 + 末尾半截标记。 */
|
|
61
|
+
export function displayClean(text: string | undefined | null): string {
|
|
62
|
+
return stripPartialTail(stripAllMarkers(text));
|
|
63
|
+
}
|