@folotoy/folotoy-openclaw-plugin 0.5.9 → 0.6.0
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/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +173 -42
- package/dist/index.js.map +1 -1
- package/dist/soothing.d.ts +11 -1
- package/dist/soothing.d.ts.map +1 -1
- package/dist/soothing.js +36 -8
- package/dist/soothing.js.map +1 -1
- package/dist/strip-markdown.d.ts +10 -0
- package/dist/strip-markdown.d.ts.map +1 -0
- package/dist/strip-markdown.js +43 -0
- package/dist/strip-markdown.js.map +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/config.ts +10 -0
- package/src/index.ts +162 -40
- package/src/soothing.ts +38 -8
- package/src/strip-markdown.ts +44 -0
package/dist/config.d.ts
CHANGED
|
@@ -27,11 +27,21 @@ export type FlatChannelConfig = {
|
|
|
27
27
|
mqtt_port?: number;
|
|
28
28
|
summary_enabled?: boolean;
|
|
29
29
|
summary_max_chars?: number;
|
|
30
|
+
sentence_split_enabled?: boolean;
|
|
31
|
+
sentence_split_delimiters?: string;
|
|
32
|
+
soothing_loop_enabled?: boolean;
|
|
33
|
+
soothing_loop_interval_ms?: number;
|
|
34
|
+
soothing_loop_max_count?: number;
|
|
30
35
|
};
|
|
31
36
|
export declare const DEFAULT_API_URL = "https://api.folotoy.cn";
|
|
32
37
|
export declare const DEFAULT_MQTT_HOST: string;
|
|
33
38
|
export declare const DEFAULT_MQTT_PORT = 1883;
|
|
34
39
|
export declare const DEFAULT_SUMMARY_ENABLED = true;
|
|
35
40
|
export declare const DEFAULT_SUMMARY_MAX_CHARS = 200;
|
|
41
|
+
export declare const DEFAULT_SENTENCE_SPLIT_ENABLED = true;
|
|
42
|
+
export declare const DEFAULT_SENTENCE_SPLIT_DELIMITERS = "\uFF01\u3002\uFF1F\uFF1B!.?;~";
|
|
43
|
+
export declare const DEFAULT_SOOTHING_LOOP_ENABLED = true;
|
|
44
|
+
export declare const DEFAULT_SOOTHING_LOOP_INTERVAL_MS = 200;
|
|
45
|
+
export declare const DEFAULT_SOOTHING_LOOP_MAX_COUNT = 3;
|
|
36
46
|
export declare function flatToPluginConfig(flat: FlatChannelConfig): PluginConfig;
|
|
37
47
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,KAAK,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,eAAe,GAAG,eAAe,CAAA;IACvC,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;CACF,CAAA;AAED,8DAA8D;AAC9D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,KAAK,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,eAAe,GAAG,eAAe,CAAA;IACvC,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAA;KACb,CAAA;CACF,CAAA;AAED,8DAA8D;AAC9D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,yBAAyB,CAAC,EAAE,MAAM,CAAA;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAA;CACjC,CAAA;AAED,eAAO,MAAM,eAAe,2BAA2B,CAAA;AACvD,eAAO,MAAM,iBAAiB,QAAgD,CAAA;AAC9E,eAAO,MAAM,iBAAiB,OAAO,CAAA;AACrC,eAAO,MAAM,uBAAuB,OAAO,CAAA;AAC3C,eAAO,MAAM,yBAAyB,MAAM,CAAA;AAC5C,eAAO,MAAM,8BAA8B,OAAO,CAAA;AAClD,eAAO,MAAM,iCAAiC,kCAAc,CAAA;AAC5D,eAAO,MAAM,6BAA6B,OAAO,CAAA;AACjD,eAAO,MAAM,iCAAiC,MAAM,CAAA;AACpD,eAAO,MAAM,+BAA+B,IAAI,CAAA;AAEhD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,YAAY,CAaxE"}
|
package/dist/config.js
CHANGED
|
@@ -3,6 +3,11 @@ export const DEFAULT_MQTT_HOST = process.env.FOLOTOY_MQTT_HOST ?? 'f.qrc92.cn';
|
|
|
3
3
|
export const DEFAULT_MQTT_PORT = 1883;
|
|
4
4
|
export const DEFAULT_SUMMARY_ENABLED = true;
|
|
5
5
|
export const DEFAULT_SUMMARY_MAX_CHARS = 200;
|
|
6
|
+
export const DEFAULT_SENTENCE_SPLIT_ENABLED = true;
|
|
7
|
+
export const DEFAULT_SENTENCE_SPLIT_DELIMITERS = '!。?;!.?;~';
|
|
8
|
+
export const DEFAULT_SOOTHING_LOOP_ENABLED = true;
|
|
9
|
+
export const DEFAULT_SOOTHING_LOOP_INTERVAL_MS = 200;
|
|
10
|
+
export const DEFAULT_SOOTHING_LOOP_MAX_COUNT = 3;
|
|
6
11
|
export function flatToPluginConfig(flat) {
|
|
7
12
|
const flow = flat.flow ?? 'direct';
|
|
8
13
|
const auth = flow === 'api'
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAuCA,MAAM,CAAC,MAAM,eAAe,GAAG,wBAAwB,CAAA;AACvD,MAAM,CAAC,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,YAAY,CAAA;AAC9E,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAA;AACrC,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAA;AAC3C,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAA;AAC5C,MAAM,CAAC,MAAM,8BAA8B,GAAG,IAAI,CAAA;AAClD,MAAM,CAAC,MAAM,iCAAiC,GAAG,WAAW,CAAA;AAC5D,MAAM,CAAC,MAAM,6BAA6B,GAAG,IAAI,CAAA;AACjD,MAAM,CAAC,MAAM,iCAAiC,GAAG,GAAG,CAAA;AACpD,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,CAAA;AAEhD,MAAM,UAAU,kBAAkB,CAAC,IAAuB;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAA;IAClC,MAAM,IAAI,GAAG,IAAI,KAAK,KAAK;QACzB,CAAC,CAAC,EAAE,IAAI,EAAE,KAAc,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,eAAe,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE;QAC5H,CAAC,CAAC,EAAE,IAAI,EAAE,QAAiB,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,EAAE,EAAE,CAAA;IAEvF,OAAO;QACL,IAAI;QACJ,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,SAAS,IAAI,iBAAiB;YACzC,IAAI,EAAE,IAAI,CAAC,SAAS,IAAI,iBAAiB;SAC1C;KACF,CAAA;AACH,CAAC"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAgC,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAgC,MAAM,0BAA0B,CAAA;AAyb/F,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;;;EAczF;yBAEe,KAAK,iBAAiB;AAAtC,wBAGC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveCredentials, createMqttClient, buildInboundTopic, buildOutboundTopic, buildNotificationTopic } from './mqtt.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createSoothingPicker } from './soothing.js';
|
|
3
|
+
import { stripMarkdown } from './strip-markdown.js';
|
|
4
|
+
import { DEFAULT_MQTT_HOST, DEFAULT_MQTT_PORT, DEFAULT_SUMMARY_ENABLED, DEFAULT_SUMMARY_MAX_CHARS, DEFAULT_SENTENCE_SPLIT_ENABLED, DEFAULT_SENTENCE_SPLIT_DELIMITERS, DEFAULT_SOOTHING_LOOP_ENABLED, DEFAULT_SOOTHING_LOOP_INTERVAL_MS, DEFAULT_SOOTHING_LOOP_MAX_COUNT, flatToPluginConfig } from './config.js';
|
|
4
5
|
// Per-account MQTT clients and msgId counters
|
|
5
6
|
const activeClients = new Map();
|
|
6
7
|
// Subagent reference, set at plugin registration
|
|
@@ -30,6 +31,11 @@ const folotoyChannel = {
|
|
|
30
31
|
mqtt_port: { type: 'number', default: DEFAULT_MQTT_PORT },
|
|
31
32
|
summary_enabled: { type: 'boolean', default: DEFAULT_SUMMARY_ENABLED },
|
|
32
33
|
summary_max_chars: { type: 'number', default: DEFAULT_SUMMARY_MAX_CHARS },
|
|
34
|
+
sentence_split_enabled: { type: 'boolean', default: DEFAULT_SENTENCE_SPLIT_ENABLED },
|
|
35
|
+
sentence_split_delimiters: { type: 'string', default: DEFAULT_SENTENCE_SPLIT_DELIMITERS },
|
|
36
|
+
soothing_loop_enabled: { type: 'boolean', default: DEFAULT_SOOTHING_LOOP_ENABLED },
|
|
37
|
+
soothing_loop_interval_ms: { type: 'number', default: DEFAULT_SOOTHING_LOOP_INTERVAL_MS },
|
|
38
|
+
soothing_loop_max_count: { type: 'number', default: DEFAULT_SOOTHING_LOOP_MAX_COUNT },
|
|
33
39
|
},
|
|
34
40
|
},
|
|
35
41
|
uiHints: {
|
|
@@ -42,6 +48,11 @@ const folotoyChannel = {
|
|
|
42
48
|
mqtt_port: { label: 'MQTT Port' },
|
|
43
49
|
summary_enabled: { label: 'Enable Summary' },
|
|
44
50
|
summary_max_chars: { label: 'Summary Max Characters' },
|
|
51
|
+
sentence_split_enabled: { label: 'Enable Sentence Splitting' },
|
|
52
|
+
sentence_split_delimiters: { label: 'Sentence Delimiters' },
|
|
53
|
+
soothing_loop_enabled: { label: 'Enable Soothing Loop' },
|
|
54
|
+
soothing_loop_interval_ms: { label: 'Soothing Loop Interval (ms)' },
|
|
55
|
+
soothing_loop_max_count: { label: 'Soothing Loop Max Count' },
|
|
45
56
|
},
|
|
46
57
|
},
|
|
47
58
|
config: {
|
|
@@ -86,6 +97,11 @@ const folotoyChannel = {
|
|
|
86
97
|
});
|
|
87
98
|
const summaryEnabled = account.summary_enabled ?? DEFAULT_SUMMARY_ENABLED;
|
|
88
99
|
const summaryMaxChars = account.summary_max_chars ?? DEFAULT_SUMMARY_MAX_CHARS;
|
|
100
|
+
const sentenceSplitEnabled = account.sentence_split_enabled ?? DEFAULT_SENTENCE_SPLIT_ENABLED;
|
|
101
|
+
const sentenceSplitDelimiters = account.sentence_split_delimiters ?? DEFAULT_SENTENCE_SPLIT_DELIMITERS;
|
|
102
|
+
const soothingLoopEnabled = account.soothing_loop_enabled ?? DEFAULT_SOOTHING_LOOP_ENABLED;
|
|
103
|
+
const soothingLoopIntervalMs = account.soothing_loop_interval_ms ?? DEFAULT_SOOTHING_LOOP_INTERVAL_MS;
|
|
104
|
+
const soothingLoopMaxCount = account.soothing_loop_max_count ?? DEFAULT_SOOTHING_LOOP_MAX_COUNT;
|
|
89
105
|
client.on('message', (_topic, payload) => {
|
|
90
106
|
let msg;
|
|
91
107
|
try {
|
|
@@ -98,12 +114,14 @@ const folotoyChannel = {
|
|
|
98
114
|
return;
|
|
99
115
|
const { msgId, inputParams: { text, recording_id } } = msg;
|
|
100
116
|
let order = 1;
|
|
117
|
+
// Create a per-message picker that cycles through candidates without repeats
|
|
118
|
+
const soothingPick = createSoothingPicker(text);
|
|
101
119
|
// Send a quick soothing acknowledgment before AI processing (order=1).
|
|
102
120
|
// AI replies continue from order=2.
|
|
103
121
|
const ackMsg = {
|
|
104
122
|
msgId,
|
|
105
123
|
identifier: 'chat_output',
|
|
106
|
-
outParams: { content:
|
|
124
|
+
outParams: { content: soothingPick(), recording_id, order, is_finished: false },
|
|
107
125
|
};
|
|
108
126
|
client.publish(outboundTopic, JSON.stringify(ackMsg));
|
|
109
127
|
const peer = { kind: 'direct', id: credentials.toy_sn };
|
|
@@ -127,13 +145,120 @@ const folotoyChannel = {
|
|
|
127
145
|
});
|
|
128
146
|
// dispatch using dispatchReplyFromConfig (full agent capabilities including tools)
|
|
129
147
|
void (async () => {
|
|
130
|
-
|
|
148
|
+
// Sentence-level streaming: buffer incoming text and flush complete
|
|
149
|
+
// sentences (delimited by punctuation) to the toy immediately.
|
|
150
|
+
const sentenceDelimiterRe = sentenceSplitEnabled
|
|
151
|
+
? new RegExp(`[${sentenceSplitDelimiters.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&')}]`)
|
|
152
|
+
: null;
|
|
153
|
+
let sentenceBuffer = '';
|
|
154
|
+
let totalSentChars = 0;
|
|
155
|
+
let firstSentenceFlushed = false;
|
|
156
|
+
let llmStarted = false;
|
|
157
|
+
// Send soothing replies while waiting for the LLM to start responding.
|
|
158
|
+
// Once any LLM chunk arrives, stop immediately. Max 5 soothing messages.
|
|
159
|
+
let soothingTimer = null;
|
|
160
|
+
let soothingCount = 0;
|
|
161
|
+
const stopSoothingLoop = () => {
|
|
162
|
+
if (soothingTimer) {
|
|
163
|
+
clearTimeout(soothingTimer);
|
|
164
|
+
soothingTimer = null;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const resetSoothingTimer = () => {
|
|
168
|
+
if (!soothingLoopEnabled || llmStarted || soothingCount >= soothingLoopMaxCount)
|
|
169
|
+
return;
|
|
170
|
+
if (soothingTimer)
|
|
171
|
+
clearTimeout(soothingTimer);
|
|
172
|
+
soothingTimer = setTimeout(() => {
|
|
173
|
+
if (llmStarted || soothingCount >= soothingLoopMaxCount)
|
|
174
|
+
return;
|
|
175
|
+
soothingCount++;
|
|
176
|
+
order++;
|
|
177
|
+
const extraAck = {
|
|
178
|
+
msgId,
|
|
179
|
+
identifier: 'chat_output',
|
|
180
|
+
outParams: { content: soothingPick(), recording_id, order, is_finished: false },
|
|
181
|
+
};
|
|
182
|
+
client.publish(outboundTopic, JSON.stringify(extraAck));
|
|
183
|
+
// Restart timer in case LLM stays silent even longer
|
|
184
|
+
resetSoothingTimer();
|
|
185
|
+
}, soothingLoopIntervalMs);
|
|
186
|
+
};
|
|
187
|
+
resetSoothingTimer();
|
|
188
|
+
// First sentence: split purely by punctuation (fast first response).
|
|
189
|
+
// Subsequent sentences: require a minimum length that grows with each
|
|
190
|
+
// sentence (base 20 chars, +10 per sentence), so later chunks are longer.
|
|
191
|
+
let sentenceCount = 0;
|
|
192
|
+
const minLenForSentence = () => {
|
|
193
|
+
if (sentenceCount === 0)
|
|
194
|
+
return 0; // first sentence: no minimum
|
|
195
|
+
return Math.min(100, 20 + (sentenceCount - 1) * 10);
|
|
196
|
+
};
|
|
197
|
+
const FORCE_FLUSH_LEN = 200; // force flush if buffer has no delimiter for this many chars
|
|
198
|
+
const publishSentence = (sentence) => {
|
|
199
|
+
sentenceCount++;
|
|
200
|
+
if (!firstSentenceFlushed)
|
|
201
|
+
firstSentenceFlushed = true;
|
|
202
|
+
order++;
|
|
203
|
+
totalSentChars += sentence.length;
|
|
204
|
+
const outMsg = {
|
|
205
|
+
msgId,
|
|
206
|
+
identifier: 'chat_output',
|
|
207
|
+
outParams: { content: sentence, recording_id, order, is_finished: false },
|
|
208
|
+
};
|
|
209
|
+
client.publish(outboundTopic, JSON.stringify(outMsg));
|
|
210
|
+
};
|
|
211
|
+
const flushSentences = () => {
|
|
212
|
+
if (!sentenceDelimiterRe)
|
|
213
|
+
return;
|
|
214
|
+
while (true) {
|
|
215
|
+
const minLen = minLenForSentence();
|
|
216
|
+
// Search for a delimiter that is at or beyond the minimum length
|
|
217
|
+
let idx = -1;
|
|
218
|
+
const searchFrom = Math.max(0, minLen - 1);
|
|
219
|
+
if (searchFrom < sentenceBuffer.length) {
|
|
220
|
+
const sub = sentenceBuffer.slice(searchFrom);
|
|
221
|
+
const match = sub.search(sentenceDelimiterRe);
|
|
222
|
+
if (match !== -1)
|
|
223
|
+
idx = searchFrom + match;
|
|
224
|
+
}
|
|
225
|
+
if (idx !== -1) {
|
|
226
|
+
const sentence = sentenceBuffer.slice(0, idx + 1).trim();
|
|
227
|
+
sentenceBuffer = sentenceBuffer.slice(idx + 1);
|
|
228
|
+
if (sentence)
|
|
229
|
+
publishSentence(sentence);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
// No delimiter found — force flush if buffer exceeds limit
|
|
233
|
+
if (sentenceBuffer.length >= FORCE_FLUSH_LEN) {
|
|
234
|
+
// Try to break at the last space/comma for a cleaner cut
|
|
235
|
+
let cutIdx = FORCE_FLUSH_LEN;
|
|
236
|
+
const lastSpace = sentenceBuffer.lastIndexOf(' ', FORCE_FLUSH_LEN);
|
|
237
|
+
const lastComma = sentenceBuffer.lastIndexOf(',', FORCE_FLUSH_LEN);
|
|
238
|
+
const lastBreak = Math.max(lastSpace, lastComma);
|
|
239
|
+
if (lastBreak > FORCE_FLUSH_LEN / 2)
|
|
240
|
+
cutIdx = lastBreak + 1;
|
|
241
|
+
const sentence = sentenceBuffer.slice(0, cutIdx).trim();
|
|
242
|
+
sentenceBuffer = sentenceBuffer.slice(cutIdx);
|
|
243
|
+
if (sentence)
|
|
244
|
+
publishSentence(sentence);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
};
|
|
131
250
|
const dispatcher = {
|
|
132
251
|
sendToolResult: () => true,
|
|
133
252
|
sendBlockReply: () => true,
|
|
134
253
|
sendFinalReply: (payload) => {
|
|
135
|
-
if (payload.text)
|
|
136
|
-
|
|
254
|
+
if (payload.text) {
|
|
255
|
+
if (!llmStarted) {
|
|
256
|
+
llmStarted = true;
|
|
257
|
+
stopSoothingLoop();
|
|
258
|
+
}
|
|
259
|
+
sentenceBuffer += stripMarkdown(payload.text);
|
|
260
|
+
flushSentences();
|
|
261
|
+
}
|
|
137
262
|
return true;
|
|
138
263
|
},
|
|
139
264
|
waitForIdle: async () => { },
|
|
@@ -149,50 +274,56 @@ const folotoyChannel = {
|
|
|
149
274
|
dispatcher,
|
|
150
275
|
}),
|
|
151
276
|
});
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
277
|
+
// Flush remaining buffer (text after the last punctuation)
|
|
278
|
+
let remaining = sentenceBuffer.trim();
|
|
279
|
+
if (remaining) {
|
|
280
|
+
// Summarize remaining text if enabled and total response exceeds threshold
|
|
281
|
+
if (summaryEnabled && subagent && (totalSentChars + remaining.length) > summaryMaxChars) {
|
|
282
|
+
try {
|
|
283
|
+
const summarySessionKey = `folotoy-summary-${accountId}-${Date.now()}`;
|
|
284
|
+
const { runId } = await subagent.run({
|
|
285
|
+
sessionKey: summarySessionKey,
|
|
286
|
+
message: [
|
|
287
|
+
`You are an assistant that summarizes texts concisely while keeping the most important information.`,
|
|
288
|
+
`Summarize the text to approximately ${Math.max(50, summaryMaxChars - totalSentChars)} characters.`,
|
|
289
|
+
`Maintain the original tone and style. Reply only with the summary, without additional explanations.`,
|
|
290
|
+
``,
|
|
291
|
+
`<text_to_summarize>`,
|
|
292
|
+
remaining,
|
|
293
|
+
`</text_to_summarize>`,
|
|
294
|
+
].join('\n'),
|
|
295
|
+
deliver: false,
|
|
296
|
+
});
|
|
297
|
+
const result = await subagent.waitForRun({ runId, timeoutMs: 30_000 });
|
|
298
|
+
if (result.status === 'ok') {
|
|
299
|
+
const { messages } = await subagent.getSessionMessages({ sessionKey: summarySessionKey, limit: 1 });
|
|
300
|
+
const lastMsg = messages[messages.length - 1];
|
|
301
|
+
const summaryText = lastMsg?.content ?? lastMsg?.text;
|
|
302
|
+
if (summaryText)
|
|
303
|
+
remaining = summaryText;
|
|
304
|
+
}
|
|
305
|
+
await subagent.deleteSession({ sessionKey: summarySessionKey }).catch(() => { });
|
|
306
|
+
}
|
|
307
|
+
catch (err) {
|
|
308
|
+
log?.warn?.(`Summary failed, truncating text: ${String(err)}`);
|
|
309
|
+
const maxRemaining = Math.max(50, summaryMaxChars - totalSentChars);
|
|
310
|
+
remaining = `${remaining.slice(0, maxRemaining - 3)}...`;
|
|
177
311
|
}
|
|
178
|
-
await subagent.deleteSession({ sessionKey }).catch(() => { });
|
|
179
|
-
}
|
|
180
|
-
catch (err) {
|
|
181
|
-
log?.warn?.(`Summary failed, truncating text: ${String(err)}`);
|
|
182
|
-
finalText = `${finalText.slice(0, summaryMaxChars - 3)}...`;
|
|
183
312
|
}
|
|
184
|
-
}
|
|
185
|
-
if (finalText) {
|
|
186
313
|
order++;
|
|
187
314
|
const outMsg = {
|
|
188
315
|
msgId,
|
|
189
316
|
identifier: 'chat_output',
|
|
190
|
-
outParams: { content:
|
|
317
|
+
outParams: { content: remaining, recording_id, order, is_finished: false },
|
|
191
318
|
};
|
|
192
319
|
client.publish(outboundTopic, JSON.stringify(outMsg));
|
|
193
320
|
}
|
|
194
321
|
}
|
|
195
322
|
finally {
|
|
323
|
+
if (soothingTimer) {
|
|
324
|
+
clearTimeout(soothingTimer);
|
|
325
|
+
soothingTimer = null;
|
|
326
|
+
}
|
|
196
327
|
order++;
|
|
197
328
|
const finishMsg = {
|
|
198
329
|
msgId,
|
|
@@ -232,7 +363,7 @@ const folotoyChannel = {
|
|
|
232
363
|
const pad = (n) => String(n).padStart(2, '0');
|
|
233
364
|
const nowLocal = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}${tzSuffix}`;
|
|
234
365
|
return [
|
|
235
|
-
`[FoloToy] This message is from a FoloToy toy (SN: ${sn}). Current time: ${nowLocal} (${tz}).`,
|
|
366
|
+
`[FoloToy] This message is from a FoloToy toy (SN: ${sn}). Current time: ${nowLocal} (${tz}). IMPORTANT: Your reply will be converted to speech (TTS). Use plain text only — no markdown, no bullet points, no numbered lists, no code blocks, no URLs. Write in a natural, conversational tone.`,
|
|
236
367
|
[
|
|
237
368
|
`To set reminders/timers, use the cron tool with action="add". IMPORTANT:`,
|
|
238
369
|
`- schedule.at MUST use the same timezone offset as current time (${tzSuffix}), NEVER use "Z"`,
|
|
@@ -272,7 +403,7 @@ const folotoyChannel = {
|
|
|
272
403
|
const notifMsg = {
|
|
273
404
|
msgId,
|
|
274
405
|
identifier: 'send_notification',
|
|
275
|
-
outParams: { text },
|
|
406
|
+
outParams: { text: stripMarkdown(text) },
|
|
276
407
|
};
|
|
277
408
|
entry.client.publish(notificationTopic, JSON.stringify(notifMsg));
|
|
278
409
|
return { channel: 'folotoy', messageId: String(msgId) };
|
|
@@ -289,7 +420,7 @@ export function sendNotification({ text, accountId }) {
|
|
|
289
420
|
const notifMsg = {
|
|
290
421
|
msgId,
|
|
291
422
|
identifier: 'send_notification',
|
|
292
|
-
outParams: { text },
|
|
423
|
+
outParams: { text: stripMarkdown(text) },
|
|
293
424
|
};
|
|
294
425
|
entry.client.publish(notificationTopic, JSON.stringify(notifMsg));
|
|
295
426
|
return { channel: 'folotoy', messageId: String(msgId) };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/soothing.d.ts
CHANGED
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
* 12 intent categories, 5 candidates each — one is chosen at random.
|
|
5
5
|
* Principles: convey "I heard you + I'm working on it", no time promises.
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Creates a soothing reply picker that guarantees no repeats until all
|
|
9
|
+
* candidates in the matched category are exhausted, then reshuffles.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* const picker = createSoothingPicker(text)
|
|
13
|
+
* picker() // first reply (no repeat)
|
|
14
|
+
* picker() // second reply (different from first)
|
|
15
|
+
*/
|
|
16
|
+
export declare function createSoothingPicker(text?: string): () => string;
|
|
7
17
|
/** Returns one randomly chosen soothing reply matching the input intent. */
|
|
8
|
-
export declare function pickSoothingReply(text
|
|
18
|
+
export declare function pickSoothingReply(text?: string): string;
|
|
9
19
|
//# sourceMappingURL=soothing.d.ts.map
|
package/dist/soothing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"soothing.d.ts","sourceRoot":"","sources":["../src/soothing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"soothing.d.ts","sourceRoot":"","sources":["../src/soothing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoJH;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,MAAM,CAmBhE;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD"}
|
package/dist/soothing.js
CHANGED
|
@@ -139,16 +139,44 @@ const DEFAULT_CANDIDATES = [
|
|
|
139
139
|
'嗯,给我一点时间想想',
|
|
140
140
|
'让我好好想想...',
|
|
141
141
|
];
|
|
142
|
-
|
|
143
|
-
|
|
142
|
+
/** Fisher-Yates shuffle (in-place) */
|
|
143
|
+
function shuffle(arr) {
|
|
144
|
+
for (let i = arr.length - 1; i > 0; i--) {
|
|
145
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
146
|
+
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
147
|
+
}
|
|
148
|
+
return arr;
|
|
144
149
|
}
|
|
145
|
-
/**
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
/**
|
|
151
|
+
* Creates a soothing reply picker that guarantees no repeats until all
|
|
152
|
+
* candidates in the matched category are exhausted, then reshuffles.
|
|
153
|
+
*
|
|
154
|
+
* Usage:
|
|
155
|
+
* const picker = createSoothingPicker(text)
|
|
156
|
+
* picker() // first reply (no repeat)
|
|
157
|
+
* picker() // second reply (different from first)
|
|
158
|
+
*/
|
|
159
|
+
export function createSoothingPicker(text) {
|
|
160
|
+
let candidates;
|
|
161
|
+
if (text) {
|
|
162
|
+
for (const rule of INTENT_RULES) {
|
|
163
|
+
if (rule.pattern.test(text)) {
|
|
164
|
+
candidates = rule.candidates;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
150
167
|
}
|
|
151
168
|
}
|
|
152
|
-
|
|
169
|
+
const pool = candidates ?? DEFAULT_CANDIDATES;
|
|
170
|
+
let queue = [];
|
|
171
|
+
return () => {
|
|
172
|
+
if (queue.length === 0) {
|
|
173
|
+
queue = shuffle([...pool]);
|
|
174
|
+
}
|
|
175
|
+
return queue.pop();
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/** Returns one randomly chosen soothing reply matching the input intent. */
|
|
179
|
+
export function pickSoothingReply(text) {
|
|
180
|
+
return createSoothingPicker(text)();
|
|
153
181
|
}
|
|
154
182
|
//# sourceMappingURL=soothing.js.map
|
package/dist/soothing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"soothing.js","sourceRoot":"","sources":["../src/soothing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,YAAY,GAAqD;IACrE;QACE,SAAS;QACT,OAAO,EAAE,gBAAgB;QACzB,UAAU,EAAE;YACV,uBAAuB;YACvB,oBAAoB;YACpB,sBAAsB;YACtB,kBAAkB;YAClB,aAAa;SACd;KACF;IACD;QACE,SAAS;QACT,OAAO,EAAE,eAAe;QACxB,UAAU,EAAE;YACV,kBAAkB;YAClB,cAAc;YACd,gBAAgB;YAChB,oBAAoB;YACpB,gBAAgB;SACjB;KACF;IACD;QACE,UAAU;QACV,OAAO,EAAE,YAAY;QACrB,UAAU,EAAE;YACV,iBAAiB;YACjB,cAAc;YACd,kBAAkB;YAClB,eAAe;YACf,iBAAiB;SAClB;KACF;IACD;QACE,SAAS;QACT,OAAO,EAAE,WAAW;QACpB,UAAU,EAAE;YACV,cAAc;YACd,eAAe;YACf,aAAa;YACb,gBAAgB;YAChB,iBAAiB;SAClB;KACF;IACD;QACE,YAAY;QACZ,OAAO,EAAE,cAAc;QACvB,UAAU,EAAE;YACV,aAAa;YACb,cAAc;YACd,gBAAgB;YAChB,aAAa;YACb,YAAY;SACb;KACF;IACD;QACE,SAAS;QACT,OAAO,EAAE,gBAAgB;QACzB,UAAU,EAAE;YACV,aAAa;YACb,cAAc;YACd,iBAAiB;YACjB,oBAAoB;YACpB,cAAc;SACf;KACF;IACD;QACE,YAAY;QACZ,OAAO,EAAE,mBAAmB;QAC5B,UAAU,EAAE;YACV,eAAe;YACf,aAAa;YACb,iBAAiB;YACjB,cAAc;YACd,YAAY;SACb;KACF;IACD;QACE,YAAY;QACZ,OAAO,EAAE,kBAAkB;QAC3B,UAAU,EAAE;YACV,YAAY;YACZ,aAAa;YACb,WAAW;YACX,cAAc;YACd,UAAU;SACX;KACF;IACD;QACE,aAAa;QACb,OAAO,EAAE,yBAAyB;QAClC,UAAU,EAAE;YACV,eAAe;YACf,eAAe;YACf,gBAAgB;YAChB,eAAe;YACf,gBAAgB;SACjB;KACF;IACD;QACE,aAAa;QACb,OAAO,EAAE,oBAAoB;QAC7B,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC;KAC9C;IACD;QACE,aAAa;QACb,OAAO,EAAE,mBAAmB;QAC5B,UAAU,EAAE;YACV,aAAa;YACb,WAAW;YACX,YAAY;YACZ,UAAU;YACV,YAAY;SACb;KACF;IACD;QACE,UAAU;QACV,OAAO,EAAE,oBAAoB;QAC7B,UAAU,EAAE;YACV,YAAY;YACZ,UAAU;YACV,UAAU;YACV,YAAY;YACZ,QAAQ;SACT;KACF;CACF,CAAA;AAED,MAAM,kBAAkB,GAAG;IACzB,UAAU;IACV,cAAc;IACd,SAAS;IACT,YAAY;IACZ,WAAW;CACZ,CAAA;AAED,SAAS,
|
|
1
|
+
{"version":3,"file":"soothing.js","sourceRoot":"","sources":["../src/soothing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip Markdown / rich-text formatting for TTS.
|
|
3
|
+
*
|
|
4
|
+
* Designed to be safe for streaming chunks — removes syntax characters
|
|
5
|
+
* individually rather than matching complete open/close patterns,
|
|
6
|
+
* so partial markdown across chunks is handled correctly.
|
|
7
|
+
* Plain text without markdown passes through unchanged.
|
|
8
|
+
*/
|
|
9
|
+
export declare function stripMarkdown(text: string): string;
|
|
10
|
+
//# sourceMappingURL=strip-markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip-markdown.d.ts","sourceRoot":"","sources":["../src/strip-markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmClD"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip Markdown / rich-text formatting for TTS.
|
|
3
|
+
*
|
|
4
|
+
* Designed to be safe for streaming chunks — removes syntax characters
|
|
5
|
+
* individually rather than matching complete open/close patterns,
|
|
6
|
+
* so partial markdown across chunks is handled correctly.
|
|
7
|
+
* Plain text without markdown passes through unchanged.
|
|
8
|
+
*/
|
|
9
|
+
export function stripMarkdown(text) {
|
|
10
|
+
return (text
|
|
11
|
+
// Code blocks (``` ... ```) — remove fences and content when complete
|
|
12
|
+
.replace(/```[\s\S]*?```/g, '')
|
|
13
|
+
// Remaining fences (incomplete code block in a chunk)
|
|
14
|
+
.replace(/```/g, '')
|
|
15
|
+
// Inline code backticks
|
|
16
|
+
.replace(/`/g, '')
|
|
17
|
+
// Images  — keep alt text
|
|
18
|
+
.replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
|
|
19
|
+
// Links [text](url) — keep text
|
|
20
|
+
.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1')
|
|
21
|
+
// Bare URLs (https://...)
|
|
22
|
+
.replace(/https?:\/\/\S+/g, '')
|
|
23
|
+
// Heading markers
|
|
24
|
+
.replace(/^#{1,6}\s*/gm, '')
|
|
25
|
+
// Bold/italic/strikethrough markers (*, _, ~)
|
|
26
|
+
.replace(/[*_~]+/g, '')
|
|
27
|
+
// Blockquote markers
|
|
28
|
+
.replace(/^>\s?/gm, '')
|
|
29
|
+
// Horizontal rules (---, ***, ___)
|
|
30
|
+
.replace(/^[-]{3,}\s*$/gm, '')
|
|
31
|
+
// Unordered list markers (- / + at line start, * already removed above)
|
|
32
|
+
.replace(/^[\s]*[-+]\s+/gm, '')
|
|
33
|
+
// Ordered list markers (1. / 2. ...)
|
|
34
|
+
.replace(/^[\s]*\d+\.\s+/gm, '')
|
|
35
|
+
// HTML tags
|
|
36
|
+
.replace(/<[^>]+>/g, '')
|
|
37
|
+
// Collapse multiple spaces
|
|
38
|
+
.replace(/ {2,}/g, ' ')
|
|
39
|
+
// Collapse multiple blank lines
|
|
40
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
41
|
+
.trim());
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=strip-markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip-markdown.js","sourceRoot":"","sources":["../src/strip-markdown.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,CACL,IAAI;QACF,sEAAsE;SACrE,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC/B,sDAAsD;SACrD,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACpB,wBAAwB;SACvB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAClB,qCAAqC;SACpC,OAAO,CAAC,yBAAyB,EAAE,IAAI,CAAC;QACzC,gCAAgC;SAC/B,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC;QACxC,0BAA0B;SACzB,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC/B,kBAAkB;SACjB,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC;QAC5B,8CAA8C;SAC7C,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;QACvB,qBAAqB;SACpB,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;QACvB,mCAAmC;SAClC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC;QAC9B,wEAAwE;SACvE,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC;QAC/B,qCAAqC;SACpC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;QAChC,YAAY;SACX,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;QACxB,2BAA2B;SAC1B,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;QACvB,gCAAgC;SAC/B,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,IAAI,EAAE,CACV,CAAA;AACH,CAAC"}
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -30,6 +30,11 @@ export type FlatChannelConfig = {
|
|
|
30
30
|
mqtt_port?: number
|
|
31
31
|
summary_enabled?: boolean
|
|
32
32
|
summary_max_chars?: number
|
|
33
|
+
sentence_split_enabled?: boolean
|
|
34
|
+
sentence_split_delimiters?: string
|
|
35
|
+
soothing_loop_enabled?: boolean
|
|
36
|
+
soothing_loop_interval_ms?: number
|
|
37
|
+
soothing_loop_max_count?: number
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
export const DEFAULT_API_URL = 'https://api.folotoy.cn'
|
|
@@ -37,6 +42,11 @@ export const DEFAULT_MQTT_HOST = process.env.FOLOTOY_MQTT_HOST ?? 'f.qrc92.cn'
|
|
|
37
42
|
export const DEFAULT_MQTT_PORT = 1883
|
|
38
43
|
export const DEFAULT_SUMMARY_ENABLED = true
|
|
39
44
|
export const DEFAULT_SUMMARY_MAX_CHARS = 200
|
|
45
|
+
export const DEFAULT_SENTENCE_SPLIT_ENABLED = true
|
|
46
|
+
export const DEFAULT_SENTENCE_SPLIT_DELIMITERS = '!。?;!.?;~'
|
|
47
|
+
export const DEFAULT_SOOTHING_LOOP_ENABLED = true
|
|
48
|
+
export const DEFAULT_SOOTHING_LOOP_INTERVAL_MS = 200
|
|
49
|
+
export const DEFAULT_SOOTHING_LOOP_MAX_COUNT = 3
|
|
40
50
|
|
|
41
51
|
export function flatToPluginConfig(flat: FlatChannelConfig): PluginConfig {
|
|
42
52
|
const flow = flat.flow ?? 'direct'
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { OpenClawPluginApi, ChannelPlugin, PluginRuntime } from 'openclaw/plugin-sdk/core'
|
|
2
2
|
import { resolveCredentials, createMqttClient, buildInboundTopic, buildOutboundTopic, buildNotificationTopic } from './mqtt.js'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { createSoothingPicker } from './soothing.js'
|
|
4
|
+
import { stripMarkdown } from './strip-markdown.js'
|
|
5
|
+
import { DEFAULT_MQTT_HOST, DEFAULT_MQTT_PORT, DEFAULT_SUMMARY_ENABLED, DEFAULT_SUMMARY_MAX_CHARS, DEFAULT_SENTENCE_SPLIT_ENABLED, DEFAULT_SENTENCE_SPLIT_DELIMITERS, DEFAULT_SOOTHING_LOOP_ENABLED, DEFAULT_SOOTHING_LOOP_INTERVAL_MS, DEFAULT_SOOTHING_LOOP_MAX_COUNT, flatToPluginConfig } from './config.js'
|
|
5
6
|
import type { FlatChannelConfig } from './config.js'
|
|
6
7
|
import type { MqttClient } from 'mqtt'
|
|
7
8
|
|
|
@@ -54,6 +55,11 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
|
|
|
54
55
|
mqtt_port: { type: 'number', default: DEFAULT_MQTT_PORT },
|
|
55
56
|
summary_enabled: { type: 'boolean', default: DEFAULT_SUMMARY_ENABLED },
|
|
56
57
|
summary_max_chars: { type: 'number', default: DEFAULT_SUMMARY_MAX_CHARS },
|
|
58
|
+
sentence_split_enabled: { type: 'boolean', default: DEFAULT_SENTENCE_SPLIT_ENABLED },
|
|
59
|
+
sentence_split_delimiters: { type: 'string', default: DEFAULT_SENTENCE_SPLIT_DELIMITERS },
|
|
60
|
+
soothing_loop_enabled: { type: 'boolean', default: DEFAULT_SOOTHING_LOOP_ENABLED },
|
|
61
|
+
soothing_loop_interval_ms: { type: 'number', default: DEFAULT_SOOTHING_LOOP_INTERVAL_MS },
|
|
62
|
+
soothing_loop_max_count: { type: 'number', default: DEFAULT_SOOTHING_LOOP_MAX_COUNT },
|
|
57
63
|
},
|
|
58
64
|
},
|
|
59
65
|
uiHints: {
|
|
@@ -66,6 +72,11 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
|
|
|
66
72
|
mqtt_port: { label: 'MQTT Port' },
|
|
67
73
|
summary_enabled: { label: 'Enable Summary' },
|
|
68
74
|
summary_max_chars: { label: 'Summary Max Characters' },
|
|
75
|
+
sentence_split_enabled: { label: 'Enable Sentence Splitting' },
|
|
76
|
+
sentence_split_delimiters: { label: 'Sentence Delimiters' },
|
|
77
|
+
soothing_loop_enabled: { label: 'Enable Soothing Loop' },
|
|
78
|
+
soothing_loop_interval_ms: { label: 'Soothing Loop Interval (ms)' },
|
|
79
|
+
soothing_loop_max_count: { label: 'Soothing Loop Max Count' },
|
|
69
80
|
},
|
|
70
81
|
},
|
|
71
82
|
config: {
|
|
@@ -115,6 +126,11 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
|
|
|
115
126
|
|
|
116
127
|
const summaryEnabled = account.summary_enabled ?? DEFAULT_SUMMARY_ENABLED
|
|
117
128
|
const summaryMaxChars = account.summary_max_chars ?? DEFAULT_SUMMARY_MAX_CHARS
|
|
129
|
+
const sentenceSplitEnabled = account.sentence_split_enabled ?? DEFAULT_SENTENCE_SPLIT_ENABLED
|
|
130
|
+
const sentenceSplitDelimiters = account.sentence_split_delimiters ?? DEFAULT_SENTENCE_SPLIT_DELIMITERS
|
|
131
|
+
const soothingLoopEnabled = account.soothing_loop_enabled ?? DEFAULT_SOOTHING_LOOP_ENABLED
|
|
132
|
+
const soothingLoopIntervalMs = account.soothing_loop_interval_ms ?? DEFAULT_SOOTHING_LOOP_INTERVAL_MS
|
|
133
|
+
const soothingLoopMaxCount = account.soothing_loop_max_count ?? DEFAULT_SOOTHING_LOOP_MAX_COUNT
|
|
118
134
|
|
|
119
135
|
client.on('message', (_topic, payload) => {
|
|
120
136
|
let msg: InboundMessage
|
|
@@ -128,12 +144,15 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
|
|
|
128
144
|
const { msgId, inputParams: { text, recording_id } } = msg
|
|
129
145
|
let order = 1
|
|
130
146
|
|
|
147
|
+
// Create a per-message picker that cycles through candidates without repeats
|
|
148
|
+
const soothingPick = createSoothingPicker(text)
|
|
149
|
+
|
|
131
150
|
// Send a quick soothing acknowledgment before AI processing (order=1).
|
|
132
151
|
// AI replies continue from order=2.
|
|
133
152
|
const ackMsg: OutboundMessage = {
|
|
134
153
|
msgId,
|
|
135
154
|
identifier: 'chat_output',
|
|
136
|
-
outParams: { content:
|
|
155
|
+
outParams: { content: soothingPick(), recording_id, order, is_finished: false },
|
|
137
156
|
}
|
|
138
157
|
client.publish(outboundTopic, JSON.stringify(ackMsg))
|
|
139
158
|
|
|
@@ -160,12 +179,113 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
|
|
|
160
179
|
|
|
161
180
|
// dispatch using dispatchReplyFromConfig (full agent capabilities including tools)
|
|
162
181
|
void (async () => {
|
|
163
|
-
|
|
182
|
+
// Sentence-level streaming: buffer incoming text and flush complete
|
|
183
|
+
// sentences (delimited by punctuation) to the toy immediately.
|
|
184
|
+
const sentenceDelimiterRe = sentenceSplitEnabled
|
|
185
|
+
? new RegExp(`[${sentenceSplitDelimiters.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&')}]`)
|
|
186
|
+
: null
|
|
187
|
+
let sentenceBuffer = ''
|
|
188
|
+
let totalSentChars = 0
|
|
189
|
+
let firstSentenceFlushed = false
|
|
190
|
+
let llmStarted = false
|
|
191
|
+
|
|
192
|
+
// Send soothing replies while waiting for the LLM to start responding.
|
|
193
|
+
// Once any LLM chunk arrives, stop immediately. Max 5 soothing messages.
|
|
194
|
+
let soothingTimer: ReturnType<typeof setTimeout> | null = null
|
|
195
|
+
let soothingCount = 0
|
|
196
|
+
const stopSoothingLoop = () => {
|
|
197
|
+
if (soothingTimer) { clearTimeout(soothingTimer); soothingTimer = null }
|
|
198
|
+
}
|
|
199
|
+
const resetSoothingTimer = () => {
|
|
200
|
+
if (!soothingLoopEnabled || llmStarted || soothingCount >= soothingLoopMaxCount) return
|
|
201
|
+
if (soothingTimer) clearTimeout(soothingTimer)
|
|
202
|
+
soothingTimer = setTimeout(() => {
|
|
203
|
+
if (llmStarted || soothingCount >= soothingLoopMaxCount) return
|
|
204
|
+
soothingCount++
|
|
205
|
+
order++
|
|
206
|
+
const extraAck: OutboundMessage = {
|
|
207
|
+
msgId,
|
|
208
|
+
identifier: 'chat_output',
|
|
209
|
+
outParams: { content: soothingPick(), recording_id, order, is_finished: false },
|
|
210
|
+
}
|
|
211
|
+
client.publish(outboundTopic, JSON.stringify(extraAck))
|
|
212
|
+
// Restart timer in case LLM stays silent even longer
|
|
213
|
+
resetSoothingTimer()
|
|
214
|
+
}, soothingLoopIntervalMs)
|
|
215
|
+
}
|
|
216
|
+
resetSoothingTimer()
|
|
217
|
+
|
|
218
|
+
// First sentence: split purely by punctuation (fast first response).
|
|
219
|
+
// Subsequent sentences: require a minimum length that grows with each
|
|
220
|
+
// sentence (base 20 chars, +10 per sentence), so later chunks are longer.
|
|
221
|
+
let sentenceCount = 0
|
|
222
|
+
const minLenForSentence = () => {
|
|
223
|
+
if (sentenceCount === 0) return 0 // first sentence: no minimum
|
|
224
|
+
return Math.min(100, 20 + (sentenceCount - 1) * 10)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const FORCE_FLUSH_LEN = 200 // force flush if buffer has no delimiter for this many chars
|
|
228
|
+
|
|
229
|
+
const publishSentence = (sentence: string) => {
|
|
230
|
+
sentenceCount++
|
|
231
|
+
if (!firstSentenceFlushed) firstSentenceFlushed = true
|
|
232
|
+
order++
|
|
233
|
+
totalSentChars += sentence.length
|
|
234
|
+
const outMsg: OutboundMessage = {
|
|
235
|
+
msgId,
|
|
236
|
+
identifier: 'chat_output',
|
|
237
|
+
outParams: { content: sentence, recording_id, order, is_finished: false },
|
|
238
|
+
}
|
|
239
|
+
client.publish(outboundTopic, JSON.stringify(outMsg))
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const flushSentences = () => {
|
|
243
|
+
if (!sentenceDelimiterRe) return
|
|
244
|
+
while (true) {
|
|
245
|
+
const minLen = minLenForSentence()
|
|
246
|
+
// Search for a delimiter that is at or beyond the minimum length
|
|
247
|
+
let idx = -1
|
|
248
|
+
const searchFrom = Math.max(0, minLen - 1)
|
|
249
|
+
if (searchFrom < sentenceBuffer.length) {
|
|
250
|
+
const sub = sentenceBuffer.slice(searchFrom)
|
|
251
|
+
const match = sub.search(sentenceDelimiterRe)
|
|
252
|
+
if (match !== -1) idx = searchFrom + match
|
|
253
|
+
}
|
|
254
|
+
if (idx !== -1) {
|
|
255
|
+
const sentence = sentenceBuffer.slice(0, idx + 1).trim()
|
|
256
|
+
sentenceBuffer = sentenceBuffer.slice(idx + 1)
|
|
257
|
+
if (sentence) publishSentence(sentence)
|
|
258
|
+
continue
|
|
259
|
+
}
|
|
260
|
+
// No delimiter found — force flush if buffer exceeds limit
|
|
261
|
+
if (sentenceBuffer.length >= FORCE_FLUSH_LEN) {
|
|
262
|
+
// Try to break at the last space/comma for a cleaner cut
|
|
263
|
+
let cutIdx = FORCE_FLUSH_LEN
|
|
264
|
+
const lastSpace = sentenceBuffer.lastIndexOf(' ', FORCE_FLUSH_LEN)
|
|
265
|
+
const lastComma = sentenceBuffer.lastIndexOf(',', FORCE_FLUSH_LEN)
|
|
266
|
+
const lastBreak = Math.max(lastSpace, lastComma)
|
|
267
|
+
if (lastBreak > FORCE_FLUSH_LEN / 2) cutIdx = lastBreak + 1
|
|
268
|
+
const sentence = sentenceBuffer.slice(0, cutIdx).trim()
|
|
269
|
+
sentenceBuffer = sentenceBuffer.slice(cutIdx)
|
|
270
|
+
if (sentence) publishSentence(sentence)
|
|
271
|
+
continue
|
|
272
|
+
}
|
|
273
|
+
break
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
164
277
|
const dispatcher = {
|
|
165
278
|
sendToolResult: () => true,
|
|
166
279
|
sendBlockReply: () => true,
|
|
167
280
|
sendFinalReply: (payload: { text?: string }) => {
|
|
168
|
-
if (payload.text)
|
|
281
|
+
if (payload.text) {
|
|
282
|
+
if (!llmStarted) {
|
|
283
|
+
llmStarted = true
|
|
284
|
+
stopSoothingLoop()
|
|
285
|
+
}
|
|
286
|
+
sentenceBuffer += stripMarkdown(payload.text)
|
|
287
|
+
flushSentences()
|
|
288
|
+
}
|
|
169
289
|
return true
|
|
170
290
|
},
|
|
171
291
|
waitForIdle: async () => {},
|
|
@@ -183,49 +303,51 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
|
|
|
183
303
|
}),
|
|
184
304
|
})
|
|
185
305
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
306
|
+
// Flush remaining buffer (text after the last punctuation)
|
|
307
|
+
let remaining = sentenceBuffer.trim()
|
|
308
|
+
if (remaining) {
|
|
309
|
+
// Summarize remaining text if enabled and total response exceeds threshold
|
|
310
|
+
if (summaryEnabled && subagent && (totalSentChars + remaining.length) > summaryMaxChars) {
|
|
311
|
+
try {
|
|
312
|
+
const summarySessionKey = `folotoy-summary-${accountId}-${Date.now()}`
|
|
313
|
+
const { runId } = await subagent.run({
|
|
314
|
+
sessionKey: summarySessionKey,
|
|
315
|
+
message: [
|
|
316
|
+
`You are an assistant that summarizes texts concisely while keeping the most important information.`,
|
|
317
|
+
`Summarize the text to approximately ${Math.max(50, summaryMaxChars - totalSentChars)} characters.`,
|
|
318
|
+
`Maintain the original tone and style. Reply only with the summary, without additional explanations.`,
|
|
319
|
+
``,
|
|
320
|
+
`<text_to_summarize>`,
|
|
321
|
+
remaining,
|
|
322
|
+
`</text_to_summarize>`,
|
|
323
|
+
].join('\n'),
|
|
324
|
+
deliver: false,
|
|
325
|
+
})
|
|
326
|
+
const result = await subagent.waitForRun({ runId, timeoutMs: 30_000 })
|
|
327
|
+
if (result.status === 'ok') {
|
|
328
|
+
const { messages } = await subagent.getSessionMessages({ sessionKey: summarySessionKey, limit: 1 })
|
|
329
|
+
const lastMsg = messages[messages.length - 1] as { content?: string; text?: string } | undefined
|
|
330
|
+
const summaryText = lastMsg?.content ?? lastMsg?.text
|
|
331
|
+
if (summaryText) remaining = summaryText
|
|
332
|
+
}
|
|
333
|
+
await subagent.deleteSession({ sessionKey: summarySessionKey }).catch(() => {})
|
|
334
|
+
} catch (err) {
|
|
335
|
+
log?.warn?.(`Summary failed, truncating text: ${String(err)}`)
|
|
336
|
+
const maxRemaining = Math.max(50, summaryMaxChars - totalSentChars)
|
|
337
|
+
remaining = `${remaining.slice(0, maxRemaining - 3)}...`
|
|
211
338
|
}
|
|
212
|
-
await subagent.deleteSession({ sessionKey }).catch(() => {})
|
|
213
|
-
} catch (err) {
|
|
214
|
-
log?.warn?.(`Summary failed, truncating text: ${String(err)}`)
|
|
215
|
-
finalText = `${finalText.slice(0, summaryMaxChars - 3)}...`
|
|
216
339
|
}
|
|
217
|
-
}
|
|
218
340
|
|
|
219
|
-
if (finalText) {
|
|
220
341
|
order++
|
|
221
342
|
const outMsg: OutboundMessage = {
|
|
222
343
|
msgId,
|
|
223
344
|
identifier: 'chat_output',
|
|
224
|
-
outParams: { content:
|
|
345
|
+
outParams: { content: remaining, recording_id, order, is_finished: false },
|
|
225
346
|
}
|
|
226
347
|
client.publish(outboundTopic, JSON.stringify(outMsg))
|
|
227
348
|
}
|
|
228
349
|
} finally {
|
|
350
|
+
if (soothingTimer) { clearTimeout(soothingTimer); soothingTimer = null }
|
|
229
351
|
order++
|
|
230
352
|
const finishMsg: OutboundMessage = {
|
|
231
353
|
msgId,
|
|
@@ -268,7 +390,7 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
|
|
|
268
390
|
const pad = (n: number) => String(n).padStart(2, '0')
|
|
269
391
|
const nowLocal = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}${tzSuffix}`
|
|
270
392
|
return [
|
|
271
|
-
`[FoloToy] This message is from a FoloToy toy (SN: ${sn}). Current time: ${nowLocal} (${tz}).`,
|
|
393
|
+
`[FoloToy] This message is from a FoloToy toy (SN: ${sn}). Current time: ${nowLocal} (${tz}). IMPORTANT: Your reply will be converted to speech (TTS). Use plain text only — no markdown, no bullet points, no numbered lists, no code blocks, no URLs. Write in a natural, conversational tone.`,
|
|
272
394
|
[
|
|
273
395
|
`To set reminders/timers, use the cron tool with action="add". IMPORTANT:`,
|
|
274
396
|
`- schedule.at MUST use the same timezone offset as current time (${tzSuffix}), NEVER use "Z"`,
|
|
@@ -309,7 +431,7 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
|
|
|
309
431
|
const notifMsg: NotificationMessage = {
|
|
310
432
|
msgId,
|
|
311
433
|
identifier: 'send_notification',
|
|
312
|
-
outParams: { text },
|
|
434
|
+
outParams: { text: stripMarkdown(text) },
|
|
313
435
|
}
|
|
314
436
|
entry.client.publish(notificationTopic, JSON.stringify(notifMsg))
|
|
315
437
|
return { channel: 'folotoy', messageId: String(msgId) }
|
|
@@ -327,7 +449,7 @@ export function sendNotification({ text, accountId }: { text: string; accountId?
|
|
|
327
449
|
const notifMsg: NotificationMessage = {
|
|
328
450
|
msgId,
|
|
329
451
|
identifier: 'send_notification',
|
|
330
|
-
outParams: { text },
|
|
452
|
+
outParams: { text: stripMarkdown(text) },
|
|
331
453
|
}
|
|
332
454
|
entry.client.publish(notificationTopic, JSON.stringify(notifMsg))
|
|
333
455
|
return { channel: 'folotoy', messageId: String(msgId) }
|
package/src/soothing.ts
CHANGED
|
@@ -142,16 +142,46 @@ const DEFAULT_CANDIDATES = [
|
|
|
142
142
|
'让我好好想想...',
|
|
143
143
|
]
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
/** Fisher-Yates shuffle (in-place) */
|
|
146
|
+
function shuffle<T>(arr: T[]): T[] {
|
|
147
|
+
for (let i = arr.length - 1; i > 0; i--) {
|
|
148
|
+
const j = Math.floor(Math.random() * (i + 1))
|
|
149
|
+
;[arr[i], arr[j]] = [arr[j]!, arr[i]!]
|
|
150
|
+
}
|
|
151
|
+
return arr
|
|
147
152
|
}
|
|
148
153
|
|
|
149
|
-
/**
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Creates a soothing reply picker that guarantees no repeats until all
|
|
156
|
+
* candidates in the matched category are exhausted, then reshuffles.
|
|
157
|
+
*
|
|
158
|
+
* Usage:
|
|
159
|
+
* const picker = createSoothingPicker(text)
|
|
160
|
+
* picker() // first reply (no repeat)
|
|
161
|
+
* picker() // second reply (different from first)
|
|
162
|
+
*/
|
|
163
|
+
export function createSoothingPicker(text?: string): () => string {
|
|
164
|
+
let candidates: string[] | undefined
|
|
165
|
+
if (text) {
|
|
166
|
+
for (const rule of INTENT_RULES) {
|
|
167
|
+
if (rule.pattern.test(text)) {
|
|
168
|
+
candidates = rule.candidates
|
|
169
|
+
break
|
|
170
|
+
}
|
|
154
171
|
}
|
|
155
172
|
}
|
|
156
|
-
|
|
173
|
+
const pool = candidates ?? DEFAULT_CANDIDATES
|
|
174
|
+
|
|
175
|
+
let queue: string[] = []
|
|
176
|
+
return () => {
|
|
177
|
+
if (queue.length === 0) {
|
|
178
|
+
queue = shuffle([...pool])
|
|
179
|
+
}
|
|
180
|
+
return queue.pop()!
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Returns one randomly chosen soothing reply matching the input intent. */
|
|
185
|
+
export function pickSoothingReply(text?: string): string {
|
|
186
|
+
return createSoothingPicker(text)()
|
|
157
187
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip Markdown / rich-text formatting for TTS.
|
|
3
|
+
*
|
|
4
|
+
* Designed to be safe for streaming chunks — removes syntax characters
|
|
5
|
+
* individually rather than matching complete open/close patterns,
|
|
6
|
+
* so partial markdown across chunks is handled correctly.
|
|
7
|
+
* Plain text without markdown passes through unchanged.
|
|
8
|
+
*/
|
|
9
|
+
export function stripMarkdown(text: string): string {
|
|
10
|
+
return (
|
|
11
|
+
text
|
|
12
|
+
// Code blocks (``` ... ```) — remove fences and content when complete
|
|
13
|
+
.replace(/```[\s\S]*?```/g, '')
|
|
14
|
+
// Remaining fences (incomplete code block in a chunk)
|
|
15
|
+
.replace(/```/g, '')
|
|
16
|
+
// Inline code backticks
|
|
17
|
+
.replace(/`/g, '')
|
|
18
|
+
// Images  — keep alt text
|
|
19
|
+
.replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
|
|
20
|
+
// Links [text](url) — keep text
|
|
21
|
+
.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1')
|
|
22
|
+
// Bare URLs (https://...)
|
|
23
|
+
.replace(/https?:\/\/\S+/g, '')
|
|
24
|
+
// Heading markers
|
|
25
|
+
.replace(/^#{1,6}\s*/gm, '')
|
|
26
|
+
// Bold/italic/strikethrough markers (*, _, ~)
|
|
27
|
+
.replace(/[*_~]+/g, '')
|
|
28
|
+
// Blockquote markers
|
|
29
|
+
.replace(/^>\s?/gm, '')
|
|
30
|
+
// Horizontal rules (---, ***, ___)
|
|
31
|
+
.replace(/^[-]{3,}\s*$/gm, '')
|
|
32
|
+
// Unordered list markers (- / + at line start, * already removed above)
|
|
33
|
+
.replace(/^[\s]*[-+]\s+/gm, '')
|
|
34
|
+
// Ordered list markers (1. / 2. ...)
|
|
35
|
+
.replace(/^[\s]*\d+\.\s+/gm, '')
|
|
36
|
+
// HTML tags
|
|
37
|
+
.replace(/<[^>]+>/g, '')
|
|
38
|
+
// Collapse multiple spaces
|
|
39
|
+
.replace(/ {2,}/g, ' ')
|
|
40
|
+
// Collapse multiple blank lines
|
|
41
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
42
|
+
.trim()
|
|
43
|
+
)
|
|
44
|
+
}
|