openclaw-xiaoyou 1.3.1 → 1.3.3
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/package.json +1 -1
- package/src/channel.ts +41 -23
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -16,6 +16,25 @@ let _runtime: any = null;
|
|
|
16
16
|
export function setRuntime(rt: any) { _runtime = rt; }
|
|
17
17
|
export function getRuntime() { return _runtime; }
|
|
18
18
|
|
|
19
|
+
// ─── 按标点/换行拆分文本 ─────────────────────────────
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 将文本按中英文标点符号和换行符拆分为多个片段。
|
|
23
|
+
* 每个片段以标点或换行结尾(保留标点在片段内)。
|
|
24
|
+
*/
|
|
25
|
+
function splitBySentence(text: string): string[] {
|
|
26
|
+
// 匹配:中文标点(。!?;)、英文标点(.!?;)后跟空格或结尾、换行符
|
|
27
|
+
const parts = text.split(/(?<=[。!?;\n])|(?<=[.!?;]\s)/);
|
|
28
|
+
const result: string[] = [];
|
|
29
|
+
for (const part of parts) {
|
|
30
|
+
const trimmed = part;
|
|
31
|
+
if (trimmed.length > 0) {
|
|
32
|
+
result.push(trimmed);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return result.length > 0 ? result : [text];
|
|
36
|
+
}
|
|
37
|
+
|
|
19
38
|
// ─── Config Adapter ──────────────────────────────────
|
|
20
39
|
|
|
21
40
|
function getChannelConfig(cfg: any): any {
|
|
@@ -180,15 +199,10 @@ export const xiayouPlugin = {
|
|
|
180
199
|
Timestamp: Date.now(),
|
|
181
200
|
});
|
|
182
201
|
|
|
183
|
-
// 4. 分发并获取回复(流式 —
|
|
202
|
+
// 4. 分发并获取回复(流式 — 按标点拆分)
|
|
184
203
|
//
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
// 而非等全部生成完毕。每个 block(段落/代码块等)生成完成后立即 deliver。
|
|
188
|
-
// 统一使用 type="reply",通过 streamStatus 字段区分:
|
|
189
|
-
// streamStatus="chunk" — 增量片段
|
|
190
|
-
// streamStatus="end" — 流结束(text 为完整文本)
|
|
191
|
-
// 无 streamStatus — 一次性完整回复(向后兼容)
|
|
204
|
+
// Gateway 的 block streaming 会多次调用 deliver,每次一个 block。
|
|
205
|
+
// 我们在 deliver 内部进一步按标点/换行拆分,实现更细粒度的流式推送。
|
|
192
206
|
//
|
|
193
207
|
const replyMessageId = `xiaoyou-${Date.now()}`;
|
|
194
208
|
let chunkSeq = 0;
|
|
@@ -204,21 +218,25 @@ export const xiayouPlugin = {
|
|
|
204
218
|
const textToSend = payload.markdown || payload.text;
|
|
205
219
|
if (!textToSend) return;
|
|
206
220
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
+
// 按标点/换行拆分为更细的片段
|
|
222
|
+
const sentences = splitBySentence(textToSend);
|
|
223
|
+
|
|
224
|
+
for (const sentence of sentences) {
|
|
225
|
+
fullText += sentence;
|
|
226
|
+
if (_client && _client.isConnected()) {
|
|
227
|
+
_client.sendReply({
|
|
228
|
+
type: "reply",
|
|
229
|
+
conversationId,
|
|
230
|
+
messageId: replyMessageId,
|
|
231
|
+
replyToMessageId: inboundMessageId,
|
|
232
|
+
text: sentence,
|
|
233
|
+
streamStatus: "chunk",
|
|
234
|
+
seq: chunkSeq++,
|
|
235
|
+
timestamp: Date.now(),
|
|
236
|
+
});
|
|
237
|
+
}
|
|
221
238
|
}
|
|
239
|
+
logger.info(`[xiaoyou] ${sentences.length} chunks sent to ${conversationId} (total seq=${chunkSeq})`);
|
|
222
240
|
},
|
|
223
241
|
onComplete: async () => {
|
|
224
242
|
replyEndSent = true;
|
|
@@ -238,7 +256,7 @@ export const xiayouPlugin = {
|
|
|
238
256
|
},
|
|
239
257
|
});
|
|
240
258
|
|
|
241
|
-
// dispatch resolve 后,如果 onComplete
|
|
259
|
+
// dispatch resolve 后,如果 onComplete 未被调用(兼容),手动发 end
|
|
242
260
|
if (!replyEndSent && chunkSeq > 0 && _client && _client.isConnected()) {
|
|
243
261
|
_client.sendReply({
|
|
244
262
|
type: "reply",
|