@ynhcj/xiaoyi 0.0.1-beta

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.
Files changed (52) hide show
  1. package/README.md +207 -0
  2. package/dist/auth.d.ts +36 -0
  3. package/dist/auth.js +111 -0
  4. package/dist/channel.d.ts +189 -0
  5. package/dist/channel.js +354 -0
  6. package/dist/config-schema.d.ts +46 -0
  7. package/dist/config-schema.js +28 -0
  8. package/dist/file-download.d.ts +17 -0
  9. package/dist/file-download.js +69 -0
  10. package/dist/file-handler.d.ts +36 -0
  11. package/dist/file-handler.js +113 -0
  12. package/dist/index.d.ts +29 -0
  13. package/dist/index.js +49 -0
  14. package/dist/onboarding.d.ts +6 -0
  15. package/dist/onboarding.js +167 -0
  16. package/dist/push.d.ts +28 -0
  17. package/dist/push.js +135 -0
  18. package/dist/runtime.d.ts +191 -0
  19. package/dist/runtime.js +438 -0
  20. package/dist/types.d.ts +280 -0
  21. package/dist/types.js +8 -0
  22. package/dist/websocket.d.ts +219 -0
  23. package/dist/websocket.js +1068 -0
  24. package/dist/xiaoyi-media.d.ts +81 -0
  25. package/dist/xiaoyi-media.js +216 -0
  26. package/dist/xy-bot.d.ts +19 -0
  27. package/dist/xy-bot.js +277 -0
  28. package/dist/xy-client.d.ts +26 -0
  29. package/dist/xy-client.js +78 -0
  30. package/dist/xy-config.d.ts +18 -0
  31. package/dist/xy-config.js +37 -0
  32. package/dist/xy-formatter.d.ts +94 -0
  33. package/dist/xy-formatter.js +303 -0
  34. package/dist/xy-monitor.d.ts +17 -0
  35. package/dist/xy-monitor.js +194 -0
  36. package/dist/xy-parser.d.ts +49 -0
  37. package/dist/xy-parser.js +109 -0
  38. package/dist/xy-reply-dispatcher.d.ts +17 -0
  39. package/dist/xy-reply-dispatcher.js +308 -0
  40. package/dist/xy-tools/session-manager.d.ts +29 -0
  41. package/dist/xy-tools/session-manager.js +80 -0
  42. package/dist/xy-utils/config-manager.d.ts +26 -0
  43. package/dist/xy-utils/config-manager.js +61 -0
  44. package/dist/xy-utils/crypto.d.ts +8 -0
  45. package/dist/xy-utils/crypto.js +21 -0
  46. package/dist/xy-utils/logger.d.ts +6 -0
  47. package/dist/xy-utils/logger.js +37 -0
  48. package/dist/xy-utils/session.d.ts +34 -0
  49. package/dist/xy-utils/session.js +55 -0
  50. package/openclaw.plugin.json +9 -0
  51. package/package.json +73 -0
  52. package/xiaoyi.js +1 -0
@@ -0,0 +1,280 @@
1
+ export interface A2AJsonRpcRequest {
2
+ jsonrpc: "2.0";
3
+ method: string;
4
+ params: A2ARequestParams;
5
+ id: string;
6
+ }
7
+ export interface A2ARequestParams {
8
+ id: string;
9
+ sessionId: string;
10
+ agentLoginSessionId?: string;
11
+ message: A2AMessage;
12
+ }
13
+ export interface A2AMessage {
14
+ role: "user" | "assistant" | "system";
15
+ parts: A2AMessagePart[];
16
+ }
17
+ export type A2AMessagePart = A2ATextPart | A2AFilePart | A2ADataPart;
18
+ export interface A2ATextPart {
19
+ kind: "text";
20
+ text: string;
21
+ }
22
+ export interface A2AFilePart {
23
+ kind: "file";
24
+ file: {
25
+ name: string;
26
+ mimeType: string;
27
+ uri: string;
28
+ };
29
+ }
30
+ export interface A2ADataPart {
31
+ kind: "data";
32
+ data: {
33
+ event?: A2ADataEvent;
34
+ variables?: {
35
+ systemVariables?: {
36
+ push_id?: string;
37
+ };
38
+ };
39
+ [key: string]: any;
40
+ };
41
+ }
42
+ export interface A2ADataEvent {
43
+ intentName: string;
44
+ outputs: Record<string, any>;
45
+ status: "success" | "failed";
46
+ }
47
+ export interface A2AReasoningTextPart {
48
+ kind: "reasoningText";
49
+ reasoningText: string;
50
+ }
51
+ export interface A2ACommandPart {
52
+ kind: "command";
53
+ command: A2ACommand;
54
+ }
55
+ export interface A2ACommand {
56
+ header: {
57
+ namespace: string;
58
+ name: string;
59
+ };
60
+ payload: Record<string, any>;
61
+ }
62
+ export type A2AArtifactPart = A2ATextPart | A2ADataPart | A2ACommandPart | A2AReasoningTextPart;
63
+ export interface A2AArtifact {
64
+ artifactId: string;
65
+ parts: A2AArtifactPart[];
66
+ }
67
+ export interface A2ARequestMessage {
68
+ agentId: string;
69
+ jsonrpc: "2.0";
70
+ id: string;
71
+ method: "message/stream";
72
+ deviceId?: string;
73
+ conversationId?: string;
74
+ sessionId?: string;
75
+ params: {
76
+ id: string;
77
+ sessionId?: string;
78
+ agentLoginSessionId?: string;
79
+ message: {
80
+ kind?: string;
81
+ messageId?: string;
82
+ role: "user" | "agent";
83
+ parts: Array<{
84
+ kind: "text" | "file" | "data";
85
+ text?: string;
86
+ file?: {
87
+ name: string;
88
+ mimeType: string;
89
+ bytes?: string;
90
+ uri?: string;
91
+ };
92
+ data?: any;
93
+ }>;
94
+ };
95
+ };
96
+ }
97
+ export interface A2AResponseMessage {
98
+ sessionId: string;
99
+ messageId: string;
100
+ timestamp: number;
101
+ agentId: string;
102
+ sender: {
103
+ id: string;
104
+ name?: string;
105
+ type: "agent";
106
+ };
107
+ content: {
108
+ type: "text" | "image" | "audio" | "video" | "file";
109
+ text?: string;
110
+ mediaUrl?: string;
111
+ fileName?: string;
112
+ fileSize?: number;
113
+ mimeType?: string;
114
+ };
115
+ context?: {
116
+ conversationId?: string;
117
+ threadId?: string;
118
+ replyToMessageId?: string;
119
+ };
120
+ status: "success" | "error" | "processing";
121
+ error?: {
122
+ code: string;
123
+ message: string;
124
+ };
125
+ }
126
+ export interface A2AJsonRpcResponse {
127
+ jsonrpc: "2.0";
128
+ id: string;
129
+ result?: A2ATaskArtifactUpdateEvent | A2ATaskStatusUpdateEvent | A2AClearContextResult | A2ATasksCancelResult;
130
+ error?: {
131
+ code: number | string;
132
+ message: string;
133
+ };
134
+ }
135
+ export interface A2ATaskArtifactUpdateEvent {
136
+ taskId: string;
137
+ kind: "artifact-update";
138
+ append?: boolean;
139
+ lastChunk?: boolean;
140
+ final: boolean;
141
+ artifact: {
142
+ artifactId: string;
143
+ parts: Array<{
144
+ kind: "text" | "file" | "data" | "reasoningText";
145
+ text?: string;
146
+ reasoningText?: string;
147
+ file?: {
148
+ name: string;
149
+ mimeType: string;
150
+ bytes?: string;
151
+ uri?: string;
152
+ };
153
+ data?: any;
154
+ }>;
155
+ };
156
+ }
157
+ export interface A2ATaskStatusUpdateEvent {
158
+ taskId: string;
159
+ kind: "status-update";
160
+ final: boolean;
161
+ status: {
162
+ message: {
163
+ role: "agent";
164
+ parts: Array<{
165
+ kind: "text";
166
+ text: string;
167
+ }>;
168
+ };
169
+ state: "submitted" | "working" | "input-required" | "completed" | "canceled" | "failed" | "unknown";
170
+ };
171
+ }
172
+ export interface A2AClearContextResult {
173
+ status: {
174
+ state: "cleared" | "failed" | "unknown";
175
+ };
176
+ }
177
+ export interface A2ATasksCancelResult {
178
+ id: string;
179
+ status: {
180
+ state: "canceled" | "failed" | "unknown";
181
+ };
182
+ }
183
+ export interface A2AWebSocketMessage {
184
+ type: "message" | "heartbeat" | "auth" | "error";
185
+ data: A2ARequestMessage | A2AResponseMessage | any;
186
+ }
187
+ export type OutboundMessageType = "clawd_bot_init" | "agent_response" | "heartbeat";
188
+ export interface OutboundWebSocketMessage {
189
+ msgType: OutboundMessageType;
190
+ agentId: string;
191
+ sessionId?: string;
192
+ taskId?: string;
193
+ msgDetail?: string;
194
+ }
195
+ export interface A2AClearMessage {
196
+ agentId: string;
197
+ sessionId: string;
198
+ id: string;
199
+ action: "clear";
200
+ timestamp: number;
201
+ }
202
+ export interface A2ATasksCancelMessage {
203
+ agentId: string;
204
+ sessionId: string;
205
+ id: string;
206
+ action?: "tasks/cancel";
207
+ method?: "tasks/cancel";
208
+ taskId?: string;
209
+ jsonrpc?: "2.0";
210
+ conversationId?: string;
211
+ timestamp?: number;
212
+ }
213
+ export interface XiaoYiChannelConfig {
214
+ enabled: boolean;
215
+ wsUrl?: string;
216
+ wsUrl1?: string;
217
+ wsUrl2?: string;
218
+ ak: string;
219
+ sk: string;
220
+ agentId: string;
221
+ enableStreaming?: boolean;
222
+ apiId?: string;
223
+ pushId?: string;
224
+ taskTimeoutMs?: number;
225
+ /**
226
+ * Session cleanup timeout in milliseconds
227
+ * When user clears context, old sessions are cleaned up after this timeout
228
+ * Default: 1 hour (60 * 60 * 1000)
229
+ */
230
+ sessionCleanupTimeoutMs?: number;
231
+ }
232
+ export interface AuthCredentials {
233
+ ak: string;
234
+ sk: string;
235
+ timestamp: number;
236
+ signature: string;
237
+ }
238
+ export interface WebSocketConnectionState {
239
+ connected: boolean;
240
+ authenticated: boolean;
241
+ lastHeartbeat: number;
242
+ lastAppHeartbeat: number;
243
+ reconnectAttempts: number;
244
+ maxReconnectAttempts: number;
245
+ }
246
+ export declare const DEFAULT_WS_URL_1 = "wss://hag.cloud.huawei.com/openclaw/v1/ws/link";
247
+ export declare const DEFAULT_WS_URL_2 = "wss://116.63.174.231/openclaw/v1/ws/link";
248
+ export interface InternalWebSocketConfig {
249
+ wsUrl1: string;
250
+ wsUrl2: string;
251
+ agentId: string;
252
+ ak: string;
253
+ sk: string;
254
+ enableStreaming?: boolean;
255
+ sessionCleanupTimeoutMs?: number;
256
+ }
257
+ export type ServerId = 'server1' | 'server2';
258
+ export interface ServerConnectionState {
259
+ connected: boolean;
260
+ ready: boolean;
261
+ lastHeartbeat: number;
262
+ reconnectAttempts: number;
263
+ }
264
+ /**
265
+ * Session cleanup state for delayed cleanup
266
+ */
267
+ export interface SessionCleanupState {
268
+ sessionId: string;
269
+ serverId: ServerId;
270
+ markedForCleanupAt: number;
271
+ cleanupTimeoutId?: NodeJS.Timeout;
272
+ reason: 'user_cleared' | 'timeout' | 'error';
273
+ accumulatedText?: string;
274
+ }
275
+ export interface SessionBinding {
276
+ sessionId: string;
277
+ server: ServerIdentifier;
278
+ boundAt: number;
279
+ }
280
+ export type ServerIdentifier = 'server1' | 'server2';
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ // A2A Message Structure Types
3
+ // Based on: https://developer.huawei.com/consumer/cn/doc/service/message-stream-0000002505761434
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.DEFAULT_WS_URL_2 = exports.DEFAULT_WS_URL_1 = void 0;
6
+ // Dual server configuration
7
+ exports.DEFAULT_WS_URL_1 = "wss://hag.cloud.huawei.com/openclaw/v1/ws/link";
8
+ exports.DEFAULT_WS_URL_2 = "wss://116.63.174.231/openclaw/v1/ws/link";
@@ -0,0 +1,219 @@
1
+ import { EventEmitter } from "events";
2
+ import { A2AResponseMessage, OutboundWebSocketMessage, WebSocketConnectionState, XiaoYiChannelConfig, ServerId, ServerConnectionState, SessionCleanupState } from "./types.js";
3
+ export declare class XiaoYiWebSocketManager extends EventEmitter {
4
+ private ws1;
5
+ private ws2;
6
+ private state1;
7
+ private state2;
8
+ private sessionServerMap;
9
+ private sessionCleanupStateMap;
10
+ private static readonly DEFAULT_CLEANUP_TIMEOUT_MS;
11
+ private auth;
12
+ private config;
13
+ private heartbeatTimeout1?;
14
+ private heartbeatTimeout2?;
15
+ private appHeartbeatInterval?;
16
+ private reconnectTimeout1?;
17
+ private reconnectTimeout2?;
18
+ private stableConnectionTimer1?;
19
+ private stableConnectionTimer2?;
20
+ private static readonly STABLE_CONNECTION_THRESHOLD;
21
+ private activeTasks;
22
+ constructor(config: XiaoYiChannelConfig);
23
+ /**
24
+ * Check if URL is wss + IP format (skip certificate verification)
25
+ */
26
+ private isWssWithIp;
27
+ /**
28
+ * Resolve configuration with defaults and backward compatibility
29
+ */
30
+ private resolveConfig;
31
+ /**
32
+ * Connect to both WebSocket servers
33
+ */
34
+ connect(): Promise<void>;
35
+ /**
36
+ * Connect to server 1
37
+ */
38
+ private connectToServer1;
39
+ /**
40
+ * Connect to server 2
41
+ */
42
+ private connectToServer2;
43
+ /**
44
+ * Disconnect from all servers
45
+ */
46
+ disconnect(): void;
47
+ /**
48
+ * Send init message to specific server
49
+ */
50
+ private sendInitMessage;
51
+ /**
52
+ * Setup WebSocket event handlers for specific server
53
+ */
54
+ private setupWebSocketHandlers;
55
+ /**
56
+ * Extract sessionId from message based on method type
57
+ * Different methods have sessionId in different locations:
58
+ * - message/stream: sessionId in params, fallback to top-level sessionId
59
+ * - tasks/cancel: sessionId at top level
60
+ * - clearContext: sessionId at top level
61
+ */
62
+ private extractSessionId;
63
+ /**
64
+ * Handle incoming message from specific server
65
+ */
66
+ private handleIncomingMessage;
67
+ /**
68
+ * Send A2A response message with automatic routing
69
+ */
70
+ sendResponse(response: A2AResponseMessage, taskId: string, sessionId: string, isFinal?: boolean, append?: boolean): Promise<void>;
71
+ /**
72
+ * Send clear context response to specific server
73
+ */
74
+ sendClearContextResponse(requestId: string, sessionId: string, success?: boolean, targetServer?: ServerId): Promise<void>;
75
+ /**
76
+ * Send status update (for intermediate status messages, e.g., timeout warnings)
77
+ * This uses "status-update" event type which keeps the conversation active
78
+ */
79
+ sendStatusUpdate(taskId: string, sessionId: string, message: string, targetServer?: ServerId): Promise<void>;
80
+ /**
81
+ * Send PUSH message (主动推送) via HTTP API
82
+ *
83
+ * This is used when SubAgent completes execution and needs to push results to user
84
+ * independently of the original A2A request-response flow.
85
+ *
86
+ * Unlike sendResponse (which responds to a specific request via WebSocket), push messages are
87
+ * sent through HTTP API asynchronously.
88
+ *
89
+ * @param sessionId - User's session ID
90
+ * @param message - Message content to push
91
+ *
92
+ * Reference: 华为小艺推送消息 API
93
+ * TODO: 实现实际的推送消息发送逻辑
94
+ */
95
+ sendPushMessage(sessionId: string, message: string): Promise<void>;
96
+ /**
97
+ * Send an outbound WebSocket message directly.
98
+ * This is a low-level method that sends a pre-formatted OutboundWebSocketMessage.
99
+ *
100
+ * @param sessionId - Session ID for routing
101
+ * @param message - Pre-formatted outbound message
102
+ */
103
+ sendMessage(sessionId: string, message: OutboundWebSocketMessage): Promise<void>;
104
+ /**
105
+ * Send tasks cancel response to specific server
106
+ */
107
+ sendTasksCancelResponse(requestId: string, sessionId: string, success?: boolean, targetServer?: ServerId): Promise<void>;
108
+ /**
109
+ * Handle clearContext method
110
+ */
111
+ private handleClearContext;
112
+ /**
113
+ * Handle clear message (legacy format)
114
+ */
115
+ private handleClearMessage;
116
+ /**
117
+ * Handle tasks/cancel message
118
+ */
119
+ private handleTasksCancelMessage;
120
+ /**
121
+ * Convert A2AResponseMessage to JSON-RPC 2.0 format
122
+ */
123
+ private convertToJsonRpcFormat;
124
+ /**
125
+ * Check if at least one server is ready
126
+ */
127
+ isReady(): boolean;
128
+ /**
129
+ * Get combined connection state
130
+ */
131
+ getState(): WebSocketConnectionState;
132
+ /**
133
+ * Get individual server states
134
+ */
135
+ getServerStates(): {
136
+ server1: ServerConnectionState;
137
+ server2: ServerConnectionState;
138
+ };
139
+ /**
140
+ * Start protocol-level heartbeat for specific server
141
+ */
142
+ private startProtocolHeartbeat;
143
+ /**
144
+ * Clear protocol heartbeat for specific server
145
+ */
146
+ private clearProtocolHeartbeat;
147
+ /**
148
+ * Start application-level heartbeat (shared across both servers)
149
+ */
150
+ private startAppHeartbeat;
151
+ /**
152
+ * Schedule reconnection for specific server
153
+ */
154
+ private scheduleReconnect;
155
+ /**
156
+ * Clear all timers
157
+ */
158
+ private clearTimers;
159
+ /**
160
+ * Schedule a connection stability check
161
+ * Only reset reconnect counter after connection has been stable for threshold time
162
+ */
163
+ private scheduleStableConnectionCheck;
164
+ /**
165
+ * Clear the connection stability check timer
166
+ */
167
+ private clearStableConnectionCheck;
168
+ /**
169
+ * Type guard for A2A request messages
170
+ * sessionId can be in params OR at top level (fallback)
171
+ */
172
+ private isA2ARequestMessage;
173
+ /**
174
+ * Get active tasks
175
+ */
176
+ getActiveTasks(): Map<string, any>;
177
+ /**
178
+ * Remove task from active tasks
179
+ */
180
+ removeActiveTask(taskId: string): void;
181
+ /**
182
+ * Get server for a specific session
183
+ */
184
+ getServerForSession(sessionId: string): ServerId | undefined;
185
+ /**
186
+ * Remove session mapping
187
+ */
188
+ removeSession(sessionId: string): void;
189
+ /**
190
+ * Mark a session for delayed cleanup
191
+ * @param sessionId The session ID to mark for cleanup
192
+ * @param serverId The server ID associated with this session
193
+ * @param timeoutMs Timeout in milliseconds before forcing cleanup
194
+ */
195
+ private markSessionForCleanup;
196
+ /**
197
+ * Force cleanup a session immediately
198
+ * @param sessionId The session ID to cleanup
199
+ */
200
+ forceCleanupSession(sessionId: string): void;
201
+ /**
202
+ * Check if a session is pending cleanup
203
+ * @param sessionId The session ID to check
204
+ * @returns True if session is pending cleanup
205
+ */
206
+ isSessionPendingCleanup(sessionId: string): boolean;
207
+ /**
208
+ * Get cleanup state for a session
209
+ * @param sessionId The session ID to check
210
+ * @returns Cleanup state if exists, undefined otherwise
211
+ */
212
+ getSessionCleanupState(sessionId: string): SessionCleanupState | undefined;
213
+ /**
214
+ * Update accumulated text for a pending cleanup session
215
+ * @param sessionId The session ID
216
+ * @param text The accumulated text
217
+ */
218
+ updateAccumulatedTextForCleanup(sessionId: string, text: string): void;
219
+ }