@honor-claw/yoyo 1.2.0-beta.3 → 1.2.0-beta.5
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
|
@@ -337,11 +337,11 @@ export class MessageHandler {
|
|
|
337
337
|
/**
|
|
338
338
|
* 处理来自Gateway的消息,转发到云侧
|
|
339
339
|
*/
|
|
340
|
-
private handleNodeGatewayMessage = (
|
|
340
|
+
private handleNodeGatewayMessage = async (
|
|
341
341
|
sourceDeviceId: string,
|
|
342
342
|
traceInfo: YOYOClawServiceEvent["traceInfo"],
|
|
343
343
|
data: string,
|
|
344
|
-
)
|
|
344
|
+
) => {
|
|
345
345
|
const hardwareDeviceId = this.sessionManager.getHardwareDeviceId(sourceDeviceId);
|
|
346
346
|
const sessionInfo = this.sessionManager.getSession(sourceDeviceId);
|
|
347
347
|
const deviceId = sessionInfo?.sourceInfo.sourceDeviceInfo?.deviceId;
|
|
@@ -356,16 +356,36 @@ 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
|
+
|
|
362
|
+
// 收到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)}`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
359
379
|
|
|
360
380
|
useClawLogger().debug?.(
|
|
361
|
-
`${LOG_PREFIX} trans gateway msg to cloud device: ${targetDeviceId}, ${
|
|
381
|
+
`${LOG_PREFIX} trans gateway msg to cloud device: ${targetDeviceId}, ${cloudData.slice(0, 1000)}`,
|
|
362
382
|
);
|
|
363
383
|
|
|
364
384
|
const result = this.sendMessage(
|
|
365
385
|
"userMessage",
|
|
366
386
|
targetDeviceId,
|
|
367
387
|
traceInfo,
|
|
368
|
-
|
|
388
|
+
cloudData,
|
|
369
389
|
undefined,
|
|
370
390
|
deviceId,
|
|
371
391
|
);
|
|
@@ -381,6 +401,29 @@ export class MessageHandler {
|
|
|
381
401
|
}
|
|
382
402
|
};
|
|
383
403
|
|
|
404
|
+
private async handleAutoPair(): Promise<void> {
|
|
405
|
+
const adminClient = this.adminClientManager.getClient();
|
|
406
|
+
if (!adminClient) {
|
|
407
|
+
useClawLogger().warn(`${LOG_PREFIX} admin client not available for auto pair`);
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
|
|
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}`,
|
|
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`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
384
427
|
private async handleContextRequest(message: YOYOClawServiceEvent): Promise<void> {
|
|
385
428
|
const { sourceDeviceId, traceInfo } = message;
|
|
386
429
|
const msgType = message.msgType as ContextMsgType;
|
|
@@ -7,6 +7,8 @@ import type {
|
|
|
7
7
|
PrimayModelResult,
|
|
8
8
|
SessionListResult,
|
|
9
9
|
SessionItem,
|
|
10
|
+
DevicePairListResult,
|
|
11
|
+
DevicePairApproveResult,
|
|
10
12
|
} from "./types/protocol.js";
|
|
11
13
|
import { SkillStatusReport } from "./types/skills.js";
|
|
12
14
|
|
|
@@ -56,6 +58,16 @@ export class AdminGatewayClient extends ProtocolGatewayClient {
|
|
|
56
58
|
return (result.sessions?.find((session) => session?.key === "agent:main:main") ??
|
|
57
59
|
{}) as SessionItem;
|
|
58
60
|
}
|
|
61
|
+
|
|
62
|
+
async devicePairList(): Promise<DevicePairListResult> {
|
|
63
|
+
return this.sendRequest("device.pair.list", {}) as Promise<DevicePairListResult>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async devicePairApprove(requestId: string): Promise<DevicePairApproveResult> {
|
|
67
|
+
return this.sendRequest("device.pair.approve", {
|
|
68
|
+
requestId,
|
|
69
|
+
}) as Promise<DevicePairApproveResult>;
|
|
70
|
+
}
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
export default AdminGatewayClient;
|
|
@@ -41,10 +41,10 @@ export class GatewayClient {
|
|
|
41
41
|
this.onOpen();
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
this.ws.on("message", (data) => {
|
|
44
|
+
this.ws.on("message", async (data) => {
|
|
45
45
|
const dataText = rawDataToString(data);
|
|
46
|
-
this.opts.onMessage?.(dataText);
|
|
47
|
-
this.onMessage(dataText);
|
|
46
|
+
await this.opts.onMessage?.(dataText);
|
|
47
|
+
await this.onMessage(dataText);
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
this.ws.on("close", (code, reason) => {
|
|
@@ -82,7 +82,7 @@ export class GatewayClient {
|
|
|
82
82
|
|
|
83
83
|
protected onOpen(): void {}
|
|
84
84
|
|
|
85
|
-
protected onMessage(_data: string): void {}
|
|
85
|
+
protected onMessage(_data: string): void | Promise<void> {}
|
|
86
86
|
|
|
87
87
|
protected onClose(_code: number, _reason: string): void {}
|
|
88
88
|
|
|
@@ -35,7 +35,7 @@ export type GatewayClientId = (typeof GATEWAY_CLIENT_IDS)[keyof typeof GATEWAY_C
|
|
|
35
35
|
export type GatewayClientMode = (typeof GATEWAY_CLIENT_MODES)[keyof typeof GATEWAY_CLIENT_MODES];
|
|
36
36
|
|
|
37
37
|
export interface GatewayClientOptions {
|
|
38
|
-
onMessage?: (data: string) => void
|
|
38
|
+
onMessage?: (data: string) => void | Promise<void>;
|
|
39
39
|
onOpen?: () => void;
|
|
40
40
|
onClose?: (reason: string) => void;
|
|
41
41
|
onError?: (error: Error) => void;
|
|
@@ -143,3 +143,55 @@ export interface SessionItem {
|
|
|
143
143
|
deliveryContext: Object[];
|
|
144
144
|
lastChannel: string;
|
|
145
145
|
}
|
|
146
|
+
|
|
147
|
+
export interface PendingDevice {
|
|
148
|
+
requestId: string;
|
|
149
|
+
deviceId: string;
|
|
150
|
+
displayName?: string;
|
|
151
|
+
role?: string;
|
|
152
|
+
remoteIp?: string;
|
|
153
|
+
isRepair?: boolean;
|
|
154
|
+
ts?: number;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface DeviceTokenSummary {
|
|
158
|
+
id: string;
|
|
159
|
+
rotatedAtMs?: number;
|
|
160
|
+
revokedAtMs?: number;
|
|
161
|
+
lastUsedAtMs?: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface PairedDevice {
|
|
165
|
+
deviceId: string;
|
|
166
|
+
displayName?: string;
|
|
167
|
+
roles?: string[];
|
|
168
|
+
scopes?: string[];
|
|
169
|
+
remoteIp?: string;
|
|
170
|
+
tokens?: DeviceTokenSummary[];
|
|
171
|
+
createdAtMs?: number;
|
|
172
|
+
approvedAtMs?: number;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface DevicePairListResult {
|
|
176
|
+
ok: boolean;
|
|
177
|
+
pending?: PendingDevice[];
|
|
178
|
+
paired?: PairedDevice[];
|
|
179
|
+
error?: {
|
|
180
|
+
code: string;
|
|
181
|
+
message: string;
|
|
182
|
+
details?: unknown;
|
|
183
|
+
retryable?: boolean;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface DevicePairApproveResult {
|
|
188
|
+
ok: boolean;
|
|
189
|
+
requestId?: string;
|
|
190
|
+
device?: PairedDevice;
|
|
191
|
+
error?: {
|
|
192
|
+
code: string;
|
|
193
|
+
message: string;
|
|
194
|
+
details?: unknown;
|
|
195
|
+
retryable?: boolean;
|
|
196
|
+
};
|
|
197
|
+
}
|