openclaw-xiaoyou 1.3.1 → 1.3.2
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 +27 -50
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -180,20 +180,14 @@ export const xiayouPlugin = {
|
|
|
180
180
|
Timestamp: Date.now(),
|
|
181
181
|
});
|
|
182
182
|
|
|
183
|
-
// 4.
|
|
183
|
+
// 4. 分发消息给 Agent
|
|
184
184
|
//
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
// streamStatus="chunk" — 增量片段
|
|
190
|
-
// streamStatus="end" — 流结束(text 为完整文本)
|
|
191
|
-
// 无 streamStatus — 一次性完整回复(向后兼容)
|
|
185
|
+
// Block streaming 机制说明:
|
|
186
|
+
// 当 blockStreaming=true 且 Gateway 配置了 blockStreamingDefault="on" 时,
|
|
187
|
+
// Gateway 会在 LLM 生成过程中通过 outbound.send 逐块推送消息,
|
|
188
|
+
// 不经过 deliver 回调。deliver 仅在非流式场景下被调用(作为 fallback)。
|
|
192
189
|
//
|
|
193
190
|
const replyMessageId = `xiaoyou-${Date.now()}`;
|
|
194
|
-
let chunkSeq = 0;
|
|
195
|
-
let fullText = "";
|
|
196
|
-
let replyEndSent = false;
|
|
197
191
|
|
|
198
192
|
await rt.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
199
193
|
ctx: inboundCtx,
|
|
@@ -201,11 +195,10 @@ export const xiayouPlugin = {
|
|
|
201
195
|
dispatcherOptions: {
|
|
202
196
|
responsePrefix: "",
|
|
203
197
|
deliver: async (payload: any) => {
|
|
198
|
+
// Fallback: 当 block streaming 未生效时,deliver 被调用
|
|
204
199
|
const textToSend = payload.markdown || payload.text;
|
|
205
200
|
if (!textToSend) return;
|
|
206
201
|
|
|
207
|
-
fullText += (fullText ? "\n" : "") + textToSend;
|
|
208
|
-
|
|
209
202
|
if (_client && _client.isConnected()) {
|
|
210
203
|
_client.sendReply({
|
|
211
204
|
type: "reply",
|
|
@@ -213,46 +206,13 @@ export const xiayouPlugin = {
|
|
|
213
206
|
messageId: replyMessageId,
|
|
214
207
|
replyToMessageId: inboundMessageId,
|
|
215
208
|
text: textToSend,
|
|
216
|
-
streamStatus: "chunk",
|
|
217
|
-
seq: chunkSeq++,
|
|
218
209
|
timestamp: Date.now(),
|
|
219
210
|
});
|
|
220
|
-
logger.info(`[xiaoyou]
|
|
221
|
-
}
|
|
222
|
-
},
|
|
223
|
-
onComplete: async () => {
|
|
224
|
-
replyEndSent = true;
|
|
225
|
-
if (_client && _client.isConnected()) {
|
|
226
|
-
_client.sendReply({
|
|
227
|
-
type: "reply",
|
|
228
|
-
conversationId,
|
|
229
|
-
messageId: replyMessageId,
|
|
230
|
-
replyToMessageId: inboundMessageId,
|
|
231
|
-
text: fullText,
|
|
232
|
-
streamStatus: "end",
|
|
233
|
-
timestamp: Date.now(),
|
|
234
|
-
});
|
|
235
|
-
logger.info(`[xiaoyou] stream end sent to ${conversationId} (${chunkSeq} chunks)${inboundMessageId ? ` (replyTo=${inboundMessageId})` : ""}`);
|
|
211
|
+
logger.info(`[xiaoyou] reply sent to ${conversationId}${inboundMessageId ? ` (replyTo=${inboundMessageId})` : ""}`);
|
|
236
212
|
}
|
|
237
213
|
},
|
|
238
214
|
},
|
|
239
215
|
});
|
|
240
|
-
|
|
241
|
-
// dispatch resolve 后,如果 onComplete 未被调用(旧版本兼容),手动发 end
|
|
242
|
-
if (!replyEndSent && chunkSeq > 0 && _client && _client.isConnected()) {
|
|
243
|
-
_client.sendReply({
|
|
244
|
-
type: "reply",
|
|
245
|
-
conversationId,
|
|
246
|
-
messageId: replyMessageId,
|
|
247
|
-
replyToMessageId: inboundMessageId,
|
|
248
|
-
text: fullText,
|
|
249
|
-
streamStatus: "end",
|
|
250
|
-
timestamp: Date.now(),
|
|
251
|
-
});
|
|
252
|
-
logger.info(`[xiaoyou] stream end (fallback) sent to ${conversationId} (${chunkSeq} chunks)${inboundMessageId ? ` (replyTo=${inboundMessageId})` : ""}`);
|
|
253
|
-
} else if (chunkSeq === 0) {
|
|
254
|
-
logger.warn(`[xiaoyou] no reply generated for ${conversationId}`);
|
|
255
|
-
}
|
|
256
216
|
},
|
|
257
217
|
});
|
|
258
218
|
|
|
@@ -280,17 +240,34 @@ export const xiayouPlugin = {
|
|
|
280
240
|
|
|
281
241
|
// ── Outbound 出站 ──────────────────────────────────
|
|
282
242
|
outbound: {
|
|
283
|
-
send: async ({ to, payload }: any) => {
|
|
243
|
+
send: async ({ to, payload, meta, ...rest }: any) => {
|
|
284
244
|
if (!_client || !_client.isConnected()) {
|
|
285
245
|
return { ok: false, error: "xiaoyou: not connected" };
|
|
286
246
|
}
|
|
287
247
|
|
|
288
|
-
|
|
248
|
+
// 调试日志:观察 Gateway block streaming 时传入的完整参数
|
|
249
|
+
const rt = getRuntime();
|
|
250
|
+
const logger = rt?.log || console;
|
|
251
|
+
logger.info(`[xiaoyou] outbound.send called: to=${to}, payload=${JSON.stringify(payload)}, meta=${JSON.stringify(meta)}, rest=${JSON.stringify(rest)}`);
|
|
252
|
+
|
|
253
|
+
// 推断 streamStatus:
|
|
254
|
+
// Gateway block streaming 可能通过 meta 或 payload 传递流式信息
|
|
255
|
+
const streamMeta = meta?.blockStream || payload?.blockStream || meta?.stream;
|
|
256
|
+
const isFinal = streamMeta?.final ?? meta?.final ?? payload?.final;
|
|
257
|
+
const seq = streamMeta?.seq ?? meta?.seq ?? payload?.seq;
|
|
258
|
+
const streamStatus = streamMeta
|
|
259
|
+
? (isFinal ? "end" : "chunk")
|
|
260
|
+
: (meta?.isBlock ? "chunk" : undefined);
|
|
261
|
+
|
|
262
|
+
const baseReply: any = {
|
|
289
263
|
type: "reply" as const,
|
|
290
264
|
conversationId: to,
|
|
291
|
-
messageId: `xiaoyou-${Date.now()}`,
|
|
265
|
+
messageId: payload.messageId || meta?.messageId || `xiaoyou-${Date.now()}`,
|
|
266
|
+
replyToMessageId: payload.replyToMessageId || meta?.replyToMessageId,
|
|
292
267
|
agentId: payload.agentId,
|
|
293
268
|
timestamp: Date.now(),
|
|
269
|
+
...(streamStatus && { streamStatus }),
|
|
270
|
+
...(seq !== undefined && { seq }),
|
|
294
271
|
};
|
|
295
272
|
|
|
296
273
|
if (payload.kind === "text") {
|