@honor-claw/yoyo 1.2.0-beta.6 → 1.2.0-beta.8

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": "@honor-claw/yoyo",
3
- "version": "1.2.0-beta.6",
3
+ "version": "1.2.0-beta.8",
4
4
  "description": "OpenClaw Honor Yoyo connection plugin",
5
5
  "keywords": [
6
6
  "ai",
@@ -109,10 +109,11 @@ export class ClawCloudClient {
109
109
  params: ExchangeTokenParams,
110
110
  ): Promise<TokenResponseV2> {
111
111
  // 构建请求头
112
+ const traceId = uuid();
112
113
  const headers: ExchangeTokenHeaders = {
113
114
  "Content-Type": "application/json",
114
115
  "x-device-id": deviceInfo.deviceId,
115
- "x-trace-id": uuid(),
116
+ "x-trace-id": traceId,
116
117
  };
117
118
 
118
119
  let data: ExchangeTokenRequest = {};
@@ -142,7 +143,7 @@ export class ClawCloudClient {
142
143
  return response.data.data;
143
144
  }
144
145
 
145
- throw new Error(`failed to get token: ${response.data?.cnMessage}`);
146
+ throw new Error(`failed to get token: ${JSON.stringify(response.data)}, traceId: ${traceId}`);
146
147
  }
147
148
  }
148
149
 
@@ -32,7 +32,7 @@ export class ClawChannel {
32
32
  config: {
33
33
  deviceInfo: config.deviceInfo,
34
34
  onStatusEvent: this.handleStatusEvent,
35
- onReply: (message, logDeviceId) => this.cloudClient.send(message, logDeviceId),
35
+ onReply: (message) => this.cloudClient.send(message),
36
36
  },
37
37
  });
38
38
 
@@ -151,7 +151,7 @@ export class ClawCloudSocketClient {
151
151
  /**
152
152
  * 发送消息
153
153
  */
154
- send(message: YOYOClawServiceEvent, toDeviceId?: string): boolean {
154
+ send(message: YOYOClawServiceEvent): boolean {
155
155
  if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
156
156
  useClawLogger().error("[claw-cloud-socket] cannot send message: connection not open");
157
157
  return false;
@@ -165,7 +165,7 @@ export class ClawCloudSocketClient {
165
165
  } catch (error) {
166
166
  useClawLogger().error(
167
167
  `[claw-cloud-socket] failed to send message to cloud session ${message.targetDeviceId},
168
- device: ${toDeviceId}: ${error instanceof Error ? error.message : String(error)}`,
168
+ ${error instanceof Error ? error.message : String(error)}`,
169
169
  );
170
170
  return false;
171
171
  }
@@ -254,7 +254,7 @@ export class MessageHandler {
254
254
  }
255
255
  } catch (error) {
256
256
  useClawLogger().error(
257
- `${LOG_PREFIX} failed to send gateway message to ${hardwareDeviceId}: ${String(error)}, session: ${sourceDeviceId}`,
257
+ `${LOG_PREFIX} failed to send gateway message to device: ${hardwareDeviceId}, session: ${sourceDeviceId}, ${String(error)}`,
258
258
  );
259
259
  }
260
260
  }
@@ -356,43 +356,40 @@ export class MessageHandler {
356
356
  try {
357
357
  // 使用当前接收到的socket对应deviceId的来源信息
358
358
  const targetDeviceId = sessionInfo.sourceInfo.sourceDeviceId;
359
- const gatewayRawData = JSON.parse(data);
360
- let cloudData = data;
361
359
 
362
360
  // 收到NOT_PAIRED错误时,自动获取待配对设备并审批
363
- if (!gatewayRawData.ok && gatewayRawData.error?.code === "NOT_PAIRED") {
364
- try {
365
- await this.handleAutoPair();
366
- cloudData = JSON.stringify({
367
- ok: true,
368
- type: "res",
369
- id: gatewayRawData.id,
370
- payload: {
371
- type: "hello-ok",
372
- },
373
- });
374
- useClawLogger().info(`${LOG_PREFIX} auto pair succeefully`);
375
- } catch (error) {
376
- useClawLogger().error(`${LOG_PREFIX} auto pair failed: ${String(error)}`);
361
+ let rawData: Record<string, any>;
362
+ try {
363
+ rawData = JSON.parse(data);
364
+ } catch {
365
+ useClawLogger().warn(`${LOG_PREFIX} gateway message is not valid JSON`);
366
+ return;
367
+ }
368
+
369
+ if (!rawData.ok && rawData.error?.code === "NOT_PAIRED") {
370
+ const requestId = rawData.error?.details?.requestId;
371
+ if (!requestId) {
372
+ useClawLogger().warn(`${LOG_PREFIX} NOT_PAIRED without requestId, ignoring...`);
373
+ return;
374
+ }
375
+ const success = await this.handleAutoPair(requestId);
376
+ if (success) {
377
+ const bizExtInfo = { id: rawData.id, type: "reconnect-required" };
378
+ this.sendMessage("deviceControl", targetDeviceId, traceInfo, "", undefined, bizExtInfo);
379
+ useClawLogger().info(`${LOG_PREFIX} auto pair is completed, requestId: ${requestId}`);
380
+ return;
377
381
  }
378
382
  }
379
383
 
380
384
  useClawLogger().debug?.(
381
- `${LOG_PREFIX} trans gateway msg to cloud device: ${targetDeviceId}, ${cloudData.slice(0, 1000)}`,
385
+ `${LOG_PREFIX} trans gateway msg to cloud, session: ${targetDeviceId}, data: ${data.slice(0, 1000)}`,
382
386
  );
383
387
 
384
- const result = this.sendMessage(
385
- "userMessage",
386
- targetDeviceId,
387
- traceInfo,
388
- cloudData,
389
- undefined,
390
- deviceId,
391
- );
388
+ const result = this.sendMessage("userMessage", targetDeviceId, traceInfo, data);
392
389
  if (!result) {
393
- // 云socket挂了,这个gateway连接就需要取消掉,最好不要一次性把所有的gateway连接都干掉,让惰性关闭
390
+ // 云socket挂了,这个gateway连接就需要取消掉,最好不要一次性把所有的gateway连接都干掉,让惰性关闭,以及设备ID的打印放到这里了
394
391
  useClawLogger().error(
395
- `${LOG_PREFIX} failed to send message, cloud socket closed, from ${targetDeviceId}`,
392
+ `${LOG_PREFIX} failed to send message, cloud socket closed, session ${targetDeviceId}, device ${deviceId}`,
396
393
  );
397
394
  this.sessionManager.closeNodeGatewayClient(targetDeviceId);
398
395
  }
@@ -401,26 +398,25 @@ export class MessageHandler {
401
398
  }
402
399
  };
403
400
 
404
- private async handleAutoPair(): Promise<void> {
401
+ private async handleAutoPair(requestId: string): Promise<boolean> {
405
402
  const adminClient = this.adminClientManager.getClient();
406
403
  if (!adminClient) {
407
404
  useClawLogger().warn(`${LOG_PREFIX} admin client not available for auto pair`);
408
- return;
405
+ return false;
409
406
  }
410
407
 
411
- useClawLogger().info(`${LOG_PREFIX} NOT_PAIRED detected, fetching pending pair list...`);
412
- const pairList = await adminClient.devicePairList();
413
- const pendingDevices = pairList.pending ?? [];
414
-
415
- for (const device of pendingDevices) {
416
- useClawLogger().info(
417
- `${LOG_PREFIX} auto approving device: ${device.deviceId}, requestId: ${device.requestId}`,
408
+ try {
409
+ useClawLogger().info(`${LOG_PREFIX} auto pair approve, requestId: ${requestId}`);
410
+ const res = await adminClient.devicePairApprove(requestId);
411
+ if (!res.ok) {
412
+ throw new Error(JSON.stringify(res.error));
413
+ }
414
+ return true;
415
+ } catch (error) {
416
+ useClawLogger().error(
417
+ `${LOG_PREFIX} auto pair approve failed, requestId: ${requestId}, error: ${String(error)}`,
418
418
  );
419
- await adminClient.devicePairApprove(device.requestId);
420
- }
421
-
422
- if (pendingDevices.length === 0) {
423
- useClawLogger().info(`${LOG_PREFIX} no pending devices found for auto pair`);
419
+ return false;
424
420
  }
425
421
  }
426
422
 
@@ -502,9 +498,9 @@ export class MessageHandler {
502
498
  msgType: YOYOClawServiceEvent["msgType"],
503
499
  targetDeviceId: string,
504
500
  traceInfo: YOYOClawServiceEvent["traceInfo"],
505
- data: string | Record<string, unknown>,
501
+ data?: string | Record<string, unknown>,
506
502
  contexts?: YOYOClawServiceEvent["contexts"],
507
- logDeviceId?: string,
503
+ bizExtInfo?: Record<string, unknown>,
508
504
  ): boolean {
509
505
  const message: YOYOClawServiceEvent = {
510
506
  msgType,
@@ -516,8 +512,9 @@ export class MessageHandler {
516
512
  port: this.config.deviceInfo.port,
517
513
  data: typeof data === "string" ? data : JSON.stringify(data),
518
514
  contexts,
515
+ bizExtInfo,
519
516
  };
520
- return this.config.onReply(message, logDeviceId ?? targetDeviceId);
517
+ return this.config.onReply(message, targetDeviceId);
521
518
  }
522
519
 
523
520
  private validateContext(context?: YOYOClawServiceContext): {
@@ -27,7 +27,8 @@ export interface YOYOClawServiceEvent {
27
27
  | "devicePairMessage"
28
28
  | "deviceUnPairMessage"
29
29
  | "fetchContexts"
30
- | "updateContexts";
30
+ | "updateContexts"
31
+ | "deviceControl";
31
32
  /**
32
33
  * 会话轮次等追加信息,只有配对消息有
33
34
  */
@@ -38,6 +39,10 @@ export interface YOYOClawServiceEvent {
38
39
  * 上下文信息
39
40
  */
40
41
  contexts?: YOYOClawServiceContext[];
42
+ /**
43
+ * 业务扩展信息
44
+ */
45
+ bizExtInfo?: Record<string, any>;
41
46
  }
42
47
 
43
48
  /**
@@ -20,6 +20,7 @@ const ADMIN_CONFIG = {
20
20
  "operator.admin",
21
21
  "operator.read",
22
22
  "operator.write",
23
+ "operator.talk.secrets",
23
24
  "operator.approvals",
24
25
  "operator.pairing",
25
26
  ],