adp-openclaw 0.0.5 → 0.0.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adp-openclaw",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "OpenClaw demo channel plugin (Go WebSocket backend)",
5
5
  "type": "module",
6
6
  "dependencies": {
package/src/channel.ts CHANGED
@@ -92,6 +92,11 @@ export const adpOpenclawPlugin: ChannelPlugin<ResolvedAdpOpenclawAccount> = {
92
92
  reactions: false,
93
93
  threads: false,
94
94
  media: false,
95
+ /**
96
+ * blockStreaming: true 启用 SDK 的块流式功能
97
+ * SDK 会通过 deliver 回调的 info.kind="block" 传递流式块
98
+ */
99
+ blockStreaming: true,
95
100
  },
96
101
  reload: { configPrefixes: ["channels.adp-openclaw"] },
97
102
  configSchema: {
package/src/monitor.ts CHANGED
@@ -22,6 +22,8 @@ const MsgType = {
22
22
  Pong: "pong",
23
23
  Inbound: "inbound",
24
24
  Outbound: "outbound",
25
+ OutboundChunk: "outbound_chunk",
26
+ OutboundEnd: "outbound_end",
25
27
  Ack: "ack",
26
28
  Error: "error",
27
29
  ConvHistory: "conv_history",
@@ -260,29 +262,89 @@ async function connectAndHandle(params: ConnectParams): Promise<void> {
260
262
  ...userMetadata,
261
263
  });
262
264
 
265
+ // Generate unique stream ID for this response
266
+ const streamId = `stream-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
267
+ let chunkIndex = 0;
268
+ const displayName = inMsg.user?.username || inMsg.from;
269
+
263
270
  await runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
264
271
  ctx,
265
272
  cfg: cfg ?? {},
266
273
  dispatcherOptions: {
267
- deliver: async (payload: { text: string }) => {
268
- const displayName = inMsg.user?.username || inMsg.from;
269
- log?.info(`[adp-openclaw] Sending reply to ${displayName}: ${payload.text.slice(0, 50)}...`);
270
-
271
- // Send via WebSocket
272
- const outMsg: WSMessage = {
273
- type: MsgType.Outbound,
274
- requestId: generateRequestId(),
275
- payload: {
276
- to: inMsg.from,
277
- text: payload.text,
278
- conversationId: inMsg.conversationId,
279
- // Include user info in response for tracing
280
- user: inMsg.user,
281
- },
282
- timestamp: Date.now(),
283
- };
284
-
285
- ws.send(JSON.stringify(outMsg));
274
+ // Unified deliver callback - handles both streaming blocks and final reply
275
+ // SDK calls this with info.kind = "block" for streaming chunks, "final" for complete response
276
+ deliver: async (payload: { text?: string }, info?: { kind?: string }) => {
277
+ const text = payload.text || "";
278
+ const kind = info?.kind || "final";
279
+
280
+ // Handle streaming block - send chunk via WebSocket
281
+ if (kind === "block" && text) {
282
+ log?.debug?.(`[adp-openclaw] Streaming block[${chunkIndex}] to ${displayName}: ${text.slice(0, 30)}...`);
283
+
284
+ const chunkMsg: WSMessage = {
285
+ type: MsgType.OutboundChunk,
286
+ requestId: generateRequestId(),
287
+ payload: {
288
+ to: inMsg.from,
289
+ chunk: text,
290
+ conversationId: inMsg.conversationId,
291
+ streamId: streamId,
292
+ index: chunkIndex,
293
+ user: inMsg.user,
294
+ },
295
+ timestamp: Date.now(),
296
+ };
297
+
298
+ ws.send(JSON.stringify(chunkMsg));
299
+ chunkIndex++;
300
+ return;
301
+ }
302
+
303
+ // Handle tool result - log but don't send separately
304
+ if (kind === "tool") {
305
+ log?.debug?.(`[adp-openclaw] Tool result received for ${displayName}`);
306
+ return;
307
+ }
308
+
309
+ // Handle final reply
310
+ if (kind === "final") {
311
+ log?.info(`[adp-openclaw] Sending final reply to ${displayName}: ${text.slice(0, 50)}...`);
312
+
313
+ // If we have streaming chunks, send stream end message
314
+ if (chunkIndex > 0) {
315
+ const endMsg: WSMessage = {
316
+ type: MsgType.OutboundEnd,
317
+ requestId: generateRequestId(),
318
+ payload: {
319
+ to: inMsg.from,
320
+ text: text,
321
+ conversationId: inMsg.conversationId,
322
+ streamId: streamId,
323
+ totalChunks: chunkIndex,
324
+ user: inMsg.user,
325
+ },
326
+ timestamp: Date.now(),
327
+ };
328
+
329
+ ws.send(JSON.stringify(endMsg));
330
+ } else {
331
+ // No streaming chunks were sent, send as regular outbound message
332
+ const outMsg: WSMessage = {
333
+ type: MsgType.Outbound,
334
+ requestId: generateRequestId(),
335
+ payload: {
336
+ to: inMsg.from,
337
+ text: text,
338
+ conversationId: inMsg.conversationId,
339
+ // Include user info in response for tracing
340
+ user: inMsg.user,
341
+ },
342
+ timestamp: Date.now(),
343
+ };
344
+
345
+ ws.send(JSON.stringify(outMsg));
346
+ }
347
+ }
286
348
  },
287
349
  onError: (err: Error) => {
288
350
  log?.error(`[adp-openclaw] Reply error: ${err.message}`);