@ynhcj/xiaoyi 1.0.1 → 1.2.0
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/README.md +148 -146
- package/dist/auth.d.ts +27 -0
- package/dist/auth.js +92 -0
- package/dist/channel.d.ts +14 -0
- package/dist/channel.js +267 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +42 -0
- package/dist/runtime.d.ts +48 -0
- package/dist/runtime.js +124 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.js +4 -0
- package/dist/websocket.d.ts +63 -0
- package/dist/websocket.js +246 -0
- package/openclaw.plugin.json +1 -6
- package/package.json +42 -45
- package/xiaoyi.js +1 -0
- package/index.ts +0 -40
- package/scripts/dev-link.sh +0 -29
- package/tsconfig.json +0 -28
package/README.md
CHANGED
|
@@ -1,198 +1,202 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @ynhcj/xiaoyichannel
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
This plugin enables Openclaw to communicate with Huawei's A2A Gateway service, allowing AI agents to send and receive messages through Huawei's messaging infrastructure.
|
|
3
|
+
XiaoYi channel plugin for OpenClaw with A2A protocol support.
|
|
8
4
|
|
|
9
5
|
## Features
|
|
10
6
|
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
7
|
+
- WebSocket-based connection to XiaoYi servers
|
|
8
|
+
- AK/SK authentication mechanism
|
|
9
|
+
- A2A (Agent-to-Agent) message protocol support
|
|
10
|
+
- Automatic reconnection with exponential backoff
|
|
11
|
+
- Heartbeat mechanism for connection health monitoring
|
|
12
|
+
- Full integration with OpenClaw's message routing and session management
|
|
17
13
|
|
|
18
14
|
## Installation
|
|
19
15
|
|
|
16
|
+
Install the plugin in your OpenClaw project:
|
|
17
|
+
|
|
20
18
|
```bash
|
|
21
|
-
|
|
19
|
+
openclaw plugins install @ynhcj/xiaoyichannel@1.0.0
|
|
22
20
|
```
|
|
23
21
|
|
|
24
22
|
## Configuration
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
24
|
+
After installation, add the XiaoYi channel configuration to your `openclaw.json` (or `.openclawd.json`):
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"channels": {
|
|
29
|
+
"xiaoyi": {
|
|
30
|
+
"enabled": true,
|
|
31
|
+
"accounts": {
|
|
32
|
+
"default": {
|
|
33
|
+
"enabled": true,
|
|
34
|
+
"wsUrl": "wss://hag.com/ws/link",
|
|
35
|
+
"ak": "your-access-key",
|
|
36
|
+
"sk": "your-secret-key",
|
|
37
|
+
"agentId": "your-agent-id"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"agents": {
|
|
43
|
+
"bindings": [
|
|
44
|
+
{
|
|
45
|
+
"agentId": "main",
|
|
46
|
+
"match": {
|
|
47
|
+
"channel": "xiaoyi",
|
|
48
|
+
"accountId": "default"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
49
54
|
```
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
### Configuration Parameters
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
- `wsUrl`: WebSocket server URL (e.g., `wss://hag.com/ws/link`)
|
|
59
|
+
- `ak`: Access Key for authentication
|
|
60
|
+
- `sk`: Secret Key for authentication
|
|
61
|
+
- `agentId`: Your agent identifier
|
|
62
|
+
|
|
63
|
+
### Multiple Accounts
|
|
64
|
+
|
|
65
|
+
You can configure multiple XiaoYi accounts:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"channels": {
|
|
70
|
+
"xiaoyi": {
|
|
71
|
+
"enabled": true,
|
|
72
|
+
"accounts": {
|
|
73
|
+
"account1": {
|
|
74
|
+
"enabled": true,
|
|
75
|
+
"wsUrl": "wss://hag.com/ws/link",
|
|
76
|
+
"ak": "ak1",
|
|
77
|
+
"sk": "sk1",
|
|
78
|
+
"agentId": "agent1"
|
|
79
|
+
},
|
|
80
|
+
"account2": {
|
|
81
|
+
"enabled": true,
|
|
82
|
+
"wsUrl": "wss://hag.com/ws/link",
|
|
83
|
+
"ak": "ak2",
|
|
84
|
+
"sk": "sk2",
|
|
85
|
+
"agentId": "agent2"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
57
91
|
```
|
|
58
92
|
|
|
59
|
-
##
|
|
93
|
+
## A2A Protocol
|
|
94
|
+
|
|
95
|
+
This plugin implements the A2A (Agent-to-Agent) message protocol as specified in the [Huawei Message Stream documentation](https://developer.huawei.com/consumer/cn/doc/service/message-stream-0000002505761434).
|
|
60
96
|
|
|
61
|
-
###
|
|
97
|
+
### Message Structure
|
|
62
98
|
|
|
63
|
-
|
|
99
|
+
**Incoming Request Message:**
|
|
100
|
+
```json
|
|
64
101
|
{
|
|
65
|
-
"
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"timestamp": 1703145600000,
|
|
69
|
-
"messageType": "request",
|
|
70
|
-
"version": "1.0"
|
|
71
|
-
},
|
|
102
|
+
"sessionId": "session-123",
|
|
103
|
+
"messageId": "msg-456",
|
|
104
|
+
"timestamp": 1234567890,
|
|
72
105
|
"sender": {
|
|
73
|
-
"id": "
|
|
74
|
-
"name": "
|
|
106
|
+
"id": "user-id",
|
|
107
|
+
"name": "User Name",
|
|
75
108
|
"type": "user"
|
|
76
109
|
},
|
|
77
|
-
"receiver": {
|
|
78
|
-
"id": "openclaw",
|
|
79
|
-
"type": "agent"
|
|
80
|
-
},
|
|
81
110
|
"content": {
|
|
82
|
-
"
|
|
83
|
-
"text": "Hello,
|
|
84
|
-
},
|
|
85
|
-
"context": {
|
|
86
|
-
"chatType": "direct"
|
|
111
|
+
"type": "text",
|
|
112
|
+
"text": "Hello, agent!"
|
|
87
113
|
}
|
|
88
114
|
}
|
|
89
115
|
```
|
|
90
116
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
117
|
+
**Outgoing Response Message:**
|
|
118
|
+
```json
|
|
94
119
|
{
|
|
95
|
-
"
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
"messageType": "response",
|
|
100
|
-
"version": "1.0"
|
|
101
|
-
},
|
|
120
|
+
"sessionId": "session-123",
|
|
121
|
+
"messageId": "msg-789",
|
|
122
|
+
"timestamp": 1234567891,
|
|
123
|
+
"agentId": "your-agent-id",
|
|
102
124
|
"sender": {
|
|
103
|
-
"id": "
|
|
104
|
-
"name": "
|
|
125
|
+
"id": "your-agent-id",
|
|
126
|
+
"name": "OpenClaw Agent",
|
|
105
127
|
"type": "agent"
|
|
106
128
|
},
|
|
107
|
-
"receiver": {
|
|
108
|
-
"id": "user123",
|
|
109
|
-
"type": "user"
|
|
110
|
-
},
|
|
111
129
|
"content": {
|
|
112
|
-
"
|
|
113
|
-
"text": "
|
|
114
|
-
},
|
|
115
|
-
"status": {
|
|
116
|
-
"code": 200,
|
|
117
|
-
"message": "OK"
|
|
130
|
+
"type": "text",
|
|
131
|
+
"text": "Hello! How can I help you?"
|
|
118
132
|
},
|
|
119
|
-
|
|
120
|
-
"agentId": "openclaw",
|
|
121
|
-
"sessionId": "session_1234567890_def456"
|
|
133
|
+
"status": "success"
|
|
122
134
|
}
|
|
123
135
|
```
|
|
124
136
|
|
|
125
137
|
## Authentication
|
|
126
138
|
|
|
127
|
-
The plugin uses
|
|
139
|
+
The plugin uses AK/SK authentication as specified in the [Huawei Push Message documentation](https://developer.huawei.com/consumer/cn/doc/service/pushmessage-0000002505761436).
|
|
128
140
|
|
|
129
|
-
|
|
130
|
-
2. Sends an authentication message on WebSocket connection
|
|
131
|
-
3. Automatically refreshes tokens before expiration
|
|
132
|
-
4. Handles authentication failures with reconnection
|
|
141
|
+
The authentication signature is generated using HMAC-SHA256:
|
|
133
142
|
|
|
134
|
-
|
|
143
|
+
```
|
|
144
|
+
signature = HMAC-SHA256(SK, "ak={AK}×tamp={TIMESTAMP}")
|
|
145
|
+
```
|
|
135
146
|
|
|
136
|
-
|
|
137
|
-
- Backoff multiplier: 1.5x
|
|
138
|
-
- Maximum delay: 30 seconds
|
|
139
|
-
- Maximum attempts: Unlimited (configurable)
|
|
140
|
-
- Ping interval: 30 seconds
|
|
141
|
-
- Pong timeout: 10 seconds
|
|
147
|
+
## Connection Management
|
|
142
148
|
|
|
143
|
-
|
|
149
|
+
The plugin automatically manages WebSocket connections with the following features:
|
|
144
150
|
|
|
145
|
-
|
|
151
|
+
- **Automatic Reconnection**: Reconnects automatically on connection loss with exponential backoff
|
|
152
|
+
- **Heartbeat Monitoring**: Sends ping messages every 30 seconds to keep the connection alive
|
|
153
|
+
- **Connection Health**: Monitors connection status and reports health via OpenClaw's status system
|
|
154
|
+
- **Max Retry Limit**: Stops reconnection attempts after 10 failed attempts
|
|
146
155
|
|
|
147
|
-
|
|
156
|
+
## Session Management
|
|
148
157
|
|
|
149
|
-
|
|
150
|
-
import { createXiaoyiWebSocketClient } from '@openclaw/xiaoyi';
|
|
158
|
+
The plugin integrates with OpenClaw's session management system:
|
|
151
159
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
accessKeyId: 'your-key',
|
|
156
|
-
secretAccessKey: 'your-secret',
|
|
157
|
-
projectId: 'your-project',
|
|
158
|
-
agentId: 'openclaw',
|
|
159
|
-
},
|
|
160
|
-
reconnect: true,
|
|
161
|
-
onMessage: (message) => console.log('Received:', message),
|
|
162
|
-
onStateChange: (status) => console.log('Status:', status.state),
|
|
163
|
-
});
|
|
160
|
+
- Sessions are scoped by `sessionId` from incoming A2A messages
|
|
161
|
+
- Each conversation maintains its own session context
|
|
162
|
+
- Session keys are automatically generated based on OpenClaw's configuration
|
|
164
163
|
|
|
165
|
-
|
|
166
|
-
```
|
|
164
|
+
## Usage
|
|
167
165
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
// Validate incoming message
|
|
187
|
-
if (validateA2ARequest(incoming)) {
|
|
188
|
-
const openclawMsg = a2aToOpenclaw(incoming, 'default', 'openclaw');
|
|
189
|
-
}
|
|
166
|
+
Once configured, the plugin will:
|
|
167
|
+
|
|
168
|
+
1. Automatically connect to the XiaoYi WebSocket server on startup
|
|
169
|
+
2. Authenticate using the provided AK/SK credentials
|
|
170
|
+
3. Receive incoming messages via WebSocket
|
|
171
|
+
4. Route messages to the appropriate OpenClaw agent
|
|
172
|
+
5. Send agent responses back through the WebSocket connection
|
|
173
|
+
|
|
174
|
+
## Troubleshooting
|
|
175
|
+
|
|
176
|
+
### Connection Issues
|
|
177
|
+
|
|
178
|
+
Check the OpenClaw logs for connection status:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
openclaw logs
|
|
190
182
|
```
|
|
191
183
|
|
|
192
|
-
|
|
184
|
+
### Authentication Failures
|
|
185
|
+
|
|
186
|
+
Verify your AK/SK credentials are correct and have the necessary permissions.
|
|
187
|
+
|
|
188
|
+
### Message Delivery
|
|
193
189
|
|
|
194
|
-
|
|
195
|
-
|
|
190
|
+
Ensure your `agentId` is correctly configured and matches your XiaoYi account settings.
|
|
191
|
+
|
|
192
|
+
## Development
|
|
193
|
+
|
|
194
|
+
To build the plugin from source:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
npm install
|
|
198
|
+
npm run build
|
|
199
|
+
```
|
|
196
200
|
|
|
197
201
|
## License
|
|
198
202
|
|
|
@@ -200,6 +204,4 @@ MIT
|
|
|
200
204
|
|
|
201
205
|
## Support
|
|
202
206
|
|
|
203
|
-
For issues and questions
|
|
204
|
-
- GitHub Issues: [openclaw/xiaoyi-channel](https://github.com/openclaw/xiaoyi-channel/issues)
|
|
205
|
-
- Openclaw Discord: [Join our server](https://discord.gg/openclaw)
|
|
207
|
+
For issues and questions, please visit the [GitHub repository](https://github.com/ynhcj/xiaoyichannel).
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AuthCredentials } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Generate authentication signature using AK/SK mechanism
|
|
4
|
+
* Based on: https://developer.huawei.com/consumer/cn/doc/service/pushmessage-0000002505761436
|
|
5
|
+
*/
|
|
6
|
+
export declare class XiaoYiAuth {
|
|
7
|
+
private ak;
|
|
8
|
+
private sk;
|
|
9
|
+
constructor(ak: string, sk: string);
|
|
10
|
+
/**
|
|
11
|
+
* Generate authentication credentials with signature
|
|
12
|
+
*/
|
|
13
|
+
generateAuthCredentials(): AuthCredentials;
|
|
14
|
+
/**
|
|
15
|
+
* Generate HMAC-SHA256 signature
|
|
16
|
+
* Format: HMAC-SHA256(SK, "ak={AK}×tamp={TIMESTAMP}")
|
|
17
|
+
*/
|
|
18
|
+
private generateSignature;
|
|
19
|
+
/**
|
|
20
|
+
* Verify if credentials are valid
|
|
21
|
+
*/
|
|
22
|
+
verifyCredentials(credentials: AuthCredentials): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Generate authentication message for WebSocket
|
|
25
|
+
*/
|
|
26
|
+
generateAuthMessage(): any;
|
|
27
|
+
}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.XiaoYiAuth = void 0;
|
|
37
|
+
const crypto = __importStar(require("crypto"));
|
|
38
|
+
/**
|
|
39
|
+
* Generate authentication signature using AK/SK mechanism
|
|
40
|
+
* Based on: https://developer.huawei.com/consumer/cn/doc/service/pushmessage-0000002505761436
|
|
41
|
+
*/
|
|
42
|
+
class XiaoYiAuth {
|
|
43
|
+
constructor(ak, sk) {
|
|
44
|
+
this.ak = ak;
|
|
45
|
+
this.sk = sk;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Generate authentication credentials with signature
|
|
49
|
+
*/
|
|
50
|
+
generateAuthCredentials() {
|
|
51
|
+
const timestamp = Date.now();
|
|
52
|
+
const signature = this.generateSignature(timestamp);
|
|
53
|
+
return {
|
|
54
|
+
ak: this.ak,
|
|
55
|
+
sk: this.sk,
|
|
56
|
+
timestamp,
|
|
57
|
+
signature,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Generate HMAC-SHA256 signature
|
|
62
|
+
* Format: HMAC-SHA256(SK, "ak={AK}×tamp={TIMESTAMP}")
|
|
63
|
+
*/
|
|
64
|
+
generateSignature(timestamp) {
|
|
65
|
+
const stringToSign = `ak=${this.ak}×tamp=${timestamp}`;
|
|
66
|
+
const hmac = crypto.createHmac("sha256", this.sk);
|
|
67
|
+
hmac.update(stringToSign);
|
|
68
|
+
return hmac.digest("hex");
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Verify if credentials are valid
|
|
72
|
+
*/
|
|
73
|
+
verifyCredentials(credentials) {
|
|
74
|
+
const expectedSignature = this.generateSignature(credentials.timestamp);
|
|
75
|
+
return credentials.signature === expectedSignature;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Generate authentication message for WebSocket
|
|
79
|
+
*/
|
|
80
|
+
generateAuthMessage() {
|
|
81
|
+
const credentials = this.generateAuthCredentials();
|
|
82
|
+
return {
|
|
83
|
+
type: "auth",
|
|
84
|
+
data: {
|
|
85
|
+
ak: credentials.ak,
|
|
86
|
+
timestamp: credentials.timestamp,
|
|
87
|
+
signature: credentials.signature,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.XiaoYiAuth = XiaoYiAuth;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ChannelPlugin } from "openclaw";
|
|
2
|
+
import { XiaoYiAccountConfig } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Resolved XiaoYi account configuration
|
|
5
|
+
*/
|
|
6
|
+
export interface ResolvedXiaoYiAccount {
|
|
7
|
+
accountId: string;
|
|
8
|
+
config: XiaoYiAccountConfig;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* XiaoYi Channel Plugin
|
|
12
|
+
* Implements OpenClaw ChannelPlugin interface for XiaoYi A2A protocol
|
|
13
|
+
*/
|
|
14
|
+
export declare const xiaoyiPlugin: ChannelPlugin<ResolvedXiaoYiAccount>;
|