openclaw-xiaoyou 1.4.4 → 1.4.6

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": "openclaw-xiaoyou",
3
- "version": "1.4.4",
3
+ "version": "1.4.6",
4
4
  "type": "module",
5
5
  "description": "Xiaoyou channel plugin for OpenClaw — connects enterprise services via persistent outbound WebSocket",
6
6
  "openclaw": {
package/src/channel.ts CHANGED
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * xiaoyou ChannelPlugin 实现
3
3
  *
4
- * 运行在 OpenClaw Gateway 进程内,通过 gateway adapter 管理
5
- * 与企业服务的 WebSocket 连接生命周期。
4
+ * 运行�?OpenClaw Gateway 进程内,通过 gateway adapter 管理
5
+ * 与企业服务的 WebSocket 连接生命周期�?
6
6
  */
7
7
 
8
8
  import type { ResolvedAccount } from "./types.js";
9
9
  import { createEnterpriseClient, type EnterpriseClient } from "./enterprise-client.js";
10
10
 
11
- // ─── 运行时状态 ──────────────────────────────────────
11
+ // ─── 运行时状�?──────────────────────────────────────
12
12
 
13
13
  let _client: EnterpriseClient | null = null;
14
- /** 记录最后一个活跃的 conversationId,用于 cron delivery 兜底 */
14
+ /** 记录最后一个活跃的 conversationId,用�?cron delivery 兜底 */
15
15
  let _lastConversationId: string | null = null;
16
16
 
17
17
  let _runtime: any = null;
@@ -102,8 +102,8 @@ export const xiayouPlugin = {
102
102
  startAccount: async (ctx: any) => {
103
103
  const { account, cfg, log } = ctx;
104
104
 
105
- // 使用 register 时注入的 runtime(有 channel.reply 等完整 API
106
- // 注意:ctx.runtime 只有 log/error/exit,不能用它覆盖
105
+ // 使用 register 时注入的 runtime(有 channel.reply 等完�?API�?
106
+ // 注意:ctx.runtime 只有 log/error/exit,不能用它覆�?
107
107
  const section = account?.config || getChannelConfig(cfg);
108
108
  const logger = log || console;
109
109
 
@@ -139,7 +139,9 @@ export const xiayouPlugin = {
139
139
  const senderName = msg.senderName ?? msg.senderId;
140
140
  const conversationId = msg.conversationId;
141
141
  const inboundMessageId = msg.messageId;
142
+ const inboundSn = msg.sn || msg.messageId;
142
143
  const text = msg.text ?? "";
144
+ const metadata = msg.metadata ?? undefined;
143
145
 
144
146
  // 记录最后活跃的 conversationId,供 cron delivery 兜底使用
145
147
  _lastConversationId = conversationId;
@@ -153,7 +155,7 @@ export const xiayouPlugin = {
153
155
  peer: { kind: "direct", id: senderId },
154
156
  });
155
157
 
156
- // 2. 格式化入站消息
158
+ // 2. 格式化入站消�?
157
159
  const fromLabel = `${senderName} (${senderId})`;
158
160
  const envelopeOptions = rt.channel.reply.resolveEnvelopeFormatOptions(cfg);
159
161
  const body = rt.channel.reply.formatInboundEnvelope({
@@ -166,7 +168,7 @@ export const xiayouPlugin = {
166
168
  envelope: envelopeOptions,
167
169
  });
168
170
 
169
- // 3. 构建上下文
171
+ // 3. 构建上下�?
170
172
  const inboundCtx = rt.channel.reply.finalizeInboundContext({
171
173
  Body: body,
172
174
  RawBody: text,
@@ -185,10 +187,10 @@ export const xiayouPlugin = {
185
187
  Timestamp: Date.now(),
186
188
  });
187
189
 
188
- // 4. 分发并获取回复(流式 — 按标点拆分)
190
+ // 4. 分发并获取回复(流式 �?按标点拆分)
189
191
  //
190
- // Gateway block streaming 会多次调用 deliver,每次一个 block
191
- // 我们在 deliver 内部进一步按标点/换行拆分,实现更细粒度的流式推送。
192
+ // Gateway �?block streaming 会多次调�?deliver,每次一�?block�?
193
+ // 我们�?deliver 内部进一步按标点/换行拆分,实现更细粒度的流式推送�?
192
194
  //
193
195
  const replyMessageId = `xiaoyou-${Date.now()}`;
194
196
  let chunkSeq = 1;
@@ -211,9 +213,10 @@ export const xiayouPlugin = {
211
213
  type: "reply",
212
214
  conversationId,
213
215
  messageId: replyMessageId,
214
- replyToMessageId: inboundMessageId,
216
+ sn: inboundSn,
215
217
  senderId,
216
218
  text: textToSend,
219
+ ...(metadata ? { metadata } : {}),
217
220
  streamStatus: "chunk",
218
221
  seq: chunkSeq++,
219
222
  timestamp: Date.now(),
@@ -228,9 +231,10 @@ export const xiayouPlugin = {
228
231
  type: "reply",
229
232
  conversationId,
230
233
  messageId: replyMessageId,
231
- replyToMessageId: inboundMessageId,
234
+ sn: inboundSn,
232
235
  senderId,
233
236
  text: fullText,
237
+ ...(metadata ? { metadata } : {}),
234
238
  streamStatus: "end",
235
239
  timestamp: Date.now(),
236
240
  });
@@ -246,9 +250,10 @@ export const xiayouPlugin = {
246
250
  type: "reply",
247
251
  conversationId,
248
252
  messageId: replyMessageId,
249
- replyToMessageId: inboundMessageId,
253
+ sn: inboundSn,
250
254
  senderId,
251
255
  text: fullText,
256
+ ...(metadata ? { metadata } : {}),
252
257
  streamStatus: "end",
253
258
  timestamp: Date.now(),
254
259
  });
@@ -263,7 +268,7 @@ export const xiayouPlugin = {
263
268
  _client = client;
264
269
  logger.info("[xiaoyou] gateway started");
265
270
 
266
- // 保持 startAccount 挂起,直到 abortSignal 触发
271
+ // 保持 startAccount 挂起,直�?abortSignal 触发
267
272
  return new Promise<void>((resolve) => {
268
273
  if (ctx.abortSignal) {
269
274
  ctx.abortSignal.addEventListener("abort", () => {
@@ -283,7 +288,7 @@ export const xiayouPlugin = {
283
288
 
284
289
  // ── Target 解析(让 Gateway delivery 系统识别 xiaoyou target)──
285
290
  normalizeTarget: (target: string) => {
286
- // 如果 target 为空,返回默认值 "schedule",避免 Gateway "requires target"
291
+ // 如果 target 为空,返回默认�?"schedule",避�?Gateway �?"requires target"
287
292
  const normalized = (target || "schedule").replace(/^xiaoyou:/i, "");
288
293
  return { ok: true, to: normalized || "schedule" };
289
294
  },
@@ -297,7 +302,7 @@ export const xiayouPlugin = {
297
302
  hint: "conversationId (e.g. conv-125)",
298
303
  },
299
304
 
300
- // ── Outbound 出站(符合 ChannelPluginOutbound 接口)──────
305
+ // ── Outbound 出站(符�?ChannelPluginOutbound 接口)──────
301
306
  outbound: {
302
307
  deliveryMode: "direct" as const,
303
308
  textChunkLimit: 2000,
@@ -315,9 +320,8 @@ export const xiayouPlugin = {
315
320
  type: "reply" as const,
316
321
  conversationId: targetTo,
317
322
  messageId: `xiaoyou-${Date.now()}`,
318
- replyToMessageId: replyToId,
323
+ sn: replyToId,
319
324
  senderId: to,
320
- ...(replyToId ? {} : { source: "scheduled_task" as const }),
321
325
  text: text,
322
326
  timestamp: Date.now(),
323
327
  };
@@ -338,9 +342,8 @@ export const xiayouPlugin = {
338
342
  type: "reply" as const,
339
343
  conversationId: targetTo,
340
344
  messageId: `xiaoyou-${Date.now()}`,
341
- replyToMessageId: replyToId,
345
+ sn: replyToId,
342
346
  senderId: to,
343
- ...(replyToId ? {} : { source: "scheduled_task" as const }),
344
347
  text: text ?? "",
345
348
  mediaUrls: mediaUrl ? [mediaUrl] : [],
346
349
  timestamp: Date.now(),
@@ -352,7 +355,7 @@ export const xiayouPlugin = {
352
355
  },
353
356
  },
354
357
 
355
- // ── Status 状态检查 ────────────────────────────────
358
+ // ── Status 状态检�?────────────────────────────────
356
359
  status: {
357
360
  describe: async ({ account }: any) => {
358
361
  const issues: Array<{ severity: string; message: string }> = [];
package/src/types.ts CHANGED
@@ -32,6 +32,9 @@ export type InboundMessage = {
32
32
  conversationId: string;
33
33
  senderId: string;
34
34
  senderName?: string;
35
+ /** 流水号,用于请求-回复关联 */
36
+ sn?: string;
37
+ /** @deprecated 使用 sn 代替 */
35
38
  messageId?: string;
36
39
  text?: string;
37
40
  attachments?: Attachment[];
@@ -59,12 +62,17 @@ export type OutboundReply = {
59
62
  type: "reply";
60
63
  conversationId: string;
61
64
  messageId: string;
65
+ /** 流水号,关联入站消息的 sn */
66
+ sn?: string;
67
+ /** @deprecated 使用 sn 代替 */
62
68
  replyToMessageId?: string;
63
69
  senderId?: string;
64
70
  text: string;
65
71
  mediaUrls?: string[];
66
72
  agentId?: string;
67
73
  timestamp: number;
74
+ /** 业务元数据,透传企业服务端发来的自定义字段 */
75
+ metadata?: Record<string, unknown>;
68
76
  /** 消息来源标识:scheduled_task=定时任务推送,不传=正常对话回复 */
69
77
  source?: "scheduled_task";
70
78
  /** 流式标记:chunk=增量片段, end=流结束, 不传=一次性完整回复 */