@ynhcj/xiaoyi-channel 0.0.72-beta → 0.0.72-next
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/dist/index.d.ts +0 -5
- package/dist/index.js +51 -14
- package/dist/src/bot.js +27 -3
- package/dist/src/channel.js +15 -23
- package/dist/src/cspl/call-api.js +14 -11
- package/dist/src/cspl/config.js +3 -3
- package/dist/src/cspl/constants.d.ts +2 -0
- package/dist/src/cspl/constants.js +12 -0
- package/dist/src/cspl/utils.js +4 -2
- package/dist/src/file-download.js +3 -6
- package/dist/src/file-upload.js +52 -5
- package/dist/src/login-token-handler.d.ts +8 -0
- package/dist/src/login-token-handler.js +60 -0
- package/dist/src/message-queue.d.ts +17 -0
- package/dist/src/message-queue.js +51 -0
- package/dist/src/monitor.js +54 -3
- package/dist/src/outbound.js +2 -7
- package/dist/src/provider.d.ts +1 -0
- package/dist/src/provider.js +442 -43
- package/dist/src/reply-dispatcher.js +6 -0
- package/dist/src/self-evolution-handler.d.ts +7 -0
- package/dist/src/self-evolution-handler.js +141 -0
- package/dist/src/self-evolution-keyword.d.ts +9 -0
- package/dist/src/self-evolution-keyword.js +145 -0
- package/dist/src/skill-retriever/config.d.ts +4 -0
- package/dist/src/skill-retriever/config.js +23 -0
- package/dist/src/skill-retriever/hooks.d.ts +22 -0
- package/dist/src/skill-retriever/hooks.js +91 -0
- package/dist/src/skill-retriever/tool-search.d.ts +16 -0
- package/dist/src/skill-retriever/tool-search.js +159 -0
- package/dist/src/skill-retriever/types.d.ts +34 -0
- package/dist/src/skill-retriever/types.js +1 -0
- package/dist/src/task-manager.d.ts +4 -0
- package/dist/src/task-manager.js +6 -0
- package/dist/src/tools/call-device-tool.d.ts +5 -0
- package/dist/src/tools/call-device-tool.js +130 -0
- package/dist/src/tools/create-alarm-tool.js +5 -16
- package/dist/src/tools/delete-alarm-tool.js +1 -4
- package/dist/src/tools/device-tool-map.js +5 -1
- package/dist/src/tools/find-pc-devices-tool.d.ts +5 -0
- package/dist/src/tools/find-pc-devices-tool.js +98 -0
- package/dist/src/tools/get-alarm-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-alarm-tool-schema.js +11 -0
- package/dist/src/tools/get-calendar-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-calendar-tool-schema.js +9 -0
- package/dist/src/tools/get-collection-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-collection-tool-schema.js +10 -0
- package/dist/src/tools/get-contact-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-contact-tool-schema.js +11 -0
- package/dist/src/tools/get-device-file-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-device-file-tool-schema.js +10 -0
- package/dist/src/tools/get-email-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-email-tool-schema.js +9 -0
- package/dist/src/tools/get-note-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-note-tool-schema.js +10 -0
- package/dist/src/tools/get-photo-tool-schema.d.ts +16 -0
- package/dist/src/tools/get-photo-tool-schema.js +10 -0
- package/dist/src/tools/image-reading-tool.js +4 -7
- package/dist/src/tools/login-token-tool.d.ts +5 -0
- package/dist/src/tools/login-token-tool.js +136 -0
- package/dist/src/tools/modify-alarm-tool.js +10 -23
- package/dist/src/tools/query-app-message-tool.d.ts +4 -0
- package/dist/src/tools/query-app-message-tool.js +138 -0
- package/dist/src/tools/query-memory-data-tool.d.ts +4 -0
- package/dist/src/tools/query-memory-data-tool.js +154 -0
- package/dist/src/tools/query-todo-task-tool.d.ts +4 -0
- package/dist/src/tools/query-todo-task-tool.js +133 -0
- package/dist/src/tools/save-file-to-phone-tool.d.ts +5 -0
- package/dist/src/tools/save-file-to-phone-tool.js +166 -0
- package/dist/src/tools/save-media-to-gallery-tool.js +3 -7
- package/dist/src/tools/save-self-evolution-skill-tool.d.ts +1 -0
- package/dist/src/tools/save-self-evolution-skill-tool.js +412 -0
- package/dist/src/tools/schema-tool-factory.d.ts +27 -0
- package/dist/src/tools/schema-tool-factory.js +32 -0
- package/dist/src/tools/search-alarm-tool.js +6 -13
- package/dist/src/tools/search-calendar-tool.js +2 -0
- package/dist/src/tools/search-email-tool.d.ts +5 -0
- package/dist/src/tools/search-email-tool.js +137 -0
- package/dist/src/tools/search-file-tool.js +4 -4
- package/dist/src/tools/search-message-tool.js +1 -0
- package/dist/src/tools/search-photo-gallery-tool.js +2 -2
- package/dist/src/tools/send-email-tool.d.ts +4 -0
- package/dist/src/tools/send-email-tool.js +134 -0
- package/dist/src/tools/send-file-to-user-tool.js +2 -4
- package/dist/src/tools/session-manager.js +2 -0
- package/dist/src/tools/upload-file-tool.js +4 -4
- package/dist/src/tools/upload-photo-tool.js +2 -2
- package/dist/src/tools/xiaoyi-add-collection-tool.js +35 -6
- package/dist/src/tools/xiaoyi-collection-tool.js +2 -1
- package/dist/src/tools/xiaoyi-delete-collection-tool.js +1 -1
- package/dist/src/utils/runtime-manager.js +24 -2
- package/dist/src/utils/self-evolution-manager.d.ts +5 -0
- package/dist/src/utils/self-evolution-manager.js +47 -0
- package/dist/src/utils/tool-call-nudge-manager.d.ts +16 -0
- package/dist/src/utils/tool-call-nudge-manager.js +47 -0
- package/dist/src/websocket.d.ts +3 -0
- package/dist/src/websocket.js +71 -0
- package/openclaw.plugin.json +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
const SELF_EVOLUTION_ENV_FILE = "/home/sandbox/.openclaw/.xiaoyiruntime";
|
|
3
|
+
const SELF_EVOLUTION_ENV_KEY = "selfEvolutionState";
|
|
4
|
+
function parseBooleanLike(value) {
|
|
5
|
+
const normalized = value.trim().toLowerCase();
|
|
6
|
+
if (normalized === "true") {
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
if (normalized === "false") {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
class SelfEvolutionManager {
|
|
15
|
+
async isEnabled() {
|
|
16
|
+
try {
|
|
17
|
+
const envData = await fs.readFile(SELF_EVOLUTION_ENV_FILE, "utf-8");
|
|
18
|
+
for (const line of envData.split(/\r?\n/u)) {
|
|
19
|
+
const trimmed = line.trim();
|
|
20
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const eqIndex = trimmed.indexOf("=");
|
|
24
|
+
if (eqIndex === -1) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
28
|
+
if (key !== SELF_EVOLUTION_ENV_KEY) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const value = trimmed.slice(eqIndex + 1).trim();
|
|
32
|
+
const parsed = parseBooleanLike(value);
|
|
33
|
+
if (parsed !== null) {
|
|
34
|
+
return parsed;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error?.code !== "ENOENT") {
|
|
41
|
+
console.error(`[SELF_EVOLUTION] Failed to read ${SELF_EVOLUTION_ENV_FILE}:`, error);
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export const selfEvolutionManager = new SelfEvolutionManager();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type RecordToolCallResult = {
|
|
2
|
+
count: number;
|
|
3
|
+
shouldNudge: boolean;
|
|
4
|
+
};
|
|
5
|
+
declare class ToolCallNudgeManager {
|
|
6
|
+
private readonly threshold;
|
|
7
|
+
private readonly sessions;
|
|
8
|
+
constructor(threshold?: number);
|
|
9
|
+
private getSessionState;
|
|
10
|
+
recordToolCall(sessionKey: string): RecordToolCallResult;
|
|
11
|
+
tryMarkKeywordNudge(sessionKey: string): boolean;
|
|
12
|
+
clearSession(sessionKey: string): void;
|
|
13
|
+
}
|
|
14
|
+
export declare const TOOL_CALL_NUDGE_THRESHOLD = 6;
|
|
15
|
+
export declare const toolCallNudgeManager: ToolCallNudgeManager;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const DEFAULT_TOOL_CALL_NUDGE_THRESHOLD = 6;
|
|
2
|
+
class ToolCallNudgeManager {
|
|
3
|
+
threshold;
|
|
4
|
+
sessions = new Map();
|
|
5
|
+
constructor(threshold = DEFAULT_TOOL_CALL_NUDGE_THRESHOLD) {
|
|
6
|
+
this.threshold = threshold;
|
|
7
|
+
}
|
|
8
|
+
getSessionState(sessionKey) {
|
|
9
|
+
let state = this.sessions.get(sessionKey);
|
|
10
|
+
if (!state) {
|
|
11
|
+
state = {
|
|
12
|
+
count: 0,
|
|
13
|
+
nudged: false,
|
|
14
|
+
};
|
|
15
|
+
this.sessions.set(sessionKey, state);
|
|
16
|
+
}
|
|
17
|
+
return state;
|
|
18
|
+
}
|
|
19
|
+
recordToolCall(sessionKey) {
|
|
20
|
+
const state = this.getSessionState(sessionKey);
|
|
21
|
+
state.count += 1;
|
|
22
|
+
if (!state.nudged && state.count >= this.threshold) {
|
|
23
|
+
state.nudged = true;
|
|
24
|
+
return {
|
|
25
|
+
count: state.count,
|
|
26
|
+
shouldNudge: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
count: state.count,
|
|
31
|
+
shouldNudge: false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
tryMarkKeywordNudge(sessionKey) {
|
|
35
|
+
const state = this.getSessionState(sessionKey);
|
|
36
|
+
if (state.nudged) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
state.nudged = true;
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
clearSession(sessionKey) {
|
|
43
|
+
this.sessions.delete(sessionKey);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export const TOOL_CALL_NUDGE_THRESHOLD = DEFAULT_TOOL_CALL_NUDGE_THRESHOLD;
|
|
47
|
+
export const toolCallNudgeManager = new ToolCallNudgeManager();
|
package/dist/src/websocket.d.ts
CHANGED
|
@@ -46,6 +46,9 @@ export declare class XYWebSocketManager extends EventEmitter {
|
|
|
46
46
|
private heartbeat;
|
|
47
47
|
private reconnectTimer;
|
|
48
48
|
private isShuttingDown;
|
|
49
|
+
private messageQueue;
|
|
50
|
+
private isBuffering;
|
|
51
|
+
private reconnectBufferTimer;
|
|
49
52
|
private log;
|
|
50
53
|
private error;
|
|
51
54
|
private onHealthEvent?;
|
package/dist/src/websocket.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import WebSocket from "ws";
|
|
3
3
|
import { EventEmitter } from "events";
|
|
4
4
|
import { HeartbeatManager } from "./heartbeat.js";
|
|
5
|
+
import { MessageQueue } from "./message-queue.js";
|
|
5
6
|
/**
|
|
6
7
|
* Manages single WebSocket connection to XY server.
|
|
7
8
|
*
|
|
@@ -28,6 +29,10 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
28
29
|
heartbeat = null;
|
|
29
30
|
reconnectTimer = null;
|
|
30
31
|
isShuttingDown = false;
|
|
32
|
+
// Message queue for buffering during disconnection/reconnection
|
|
33
|
+
messageQueue;
|
|
34
|
+
isBuffering = false;
|
|
35
|
+
reconnectBufferTimer = null;
|
|
31
36
|
// Logging functions
|
|
32
37
|
log;
|
|
33
38
|
error;
|
|
@@ -39,6 +44,7 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
39
44
|
this.runtime = runtime;
|
|
40
45
|
this.log = runtime?.log ?? console.log;
|
|
41
46
|
this.error = runtime?.error ?? console.error;
|
|
47
|
+
this.messageQueue = new MessageQueue(this.log);
|
|
42
48
|
}
|
|
43
49
|
/**
|
|
44
50
|
* Set health event callback to report activity to OpenClaw framework.
|
|
@@ -85,6 +91,13 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
85
91
|
clearTimeout(this.reconnectTimer);
|
|
86
92
|
this.reconnectTimer = null;
|
|
87
93
|
}
|
|
94
|
+
// Clear message queue on explicit disconnect (not during reconnection)
|
|
95
|
+
if (this.reconnectBufferTimer) {
|
|
96
|
+
clearTimeout(this.reconnectBufferTimer);
|
|
97
|
+
this.reconnectBufferTimer = null;
|
|
98
|
+
}
|
|
99
|
+
this.messageQueue.clear();
|
|
100
|
+
this.isBuffering = false;
|
|
88
101
|
this.cleanupConnection();
|
|
89
102
|
this.log("Disconnected from XY WebSocket server");
|
|
90
103
|
}
|
|
@@ -92,10 +105,15 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
92
105
|
* Send a message to the server.
|
|
93
106
|
*/
|
|
94
107
|
async sendMessage(sessionId, message) {
|
|
108
|
+
if (this.isBuffering) {
|
|
109
|
+
this.messageQueue.enqueue(message);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
95
112
|
if (!this.ws || !this.state.ready || this.ws.readyState !== WebSocket.OPEN) {
|
|
96
113
|
throw new Error("WebSocket not ready");
|
|
97
114
|
}
|
|
98
115
|
const messageStr = JSON.stringify(message);
|
|
116
|
+
console.log(`[WS-SEND] Full message JSON: ${messageStr}`);
|
|
99
117
|
this.ws.send(messageStr);
|
|
100
118
|
}
|
|
101
119
|
/**
|
|
@@ -185,6 +203,11 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
185
203
|
clearTimeout(this.reconnectTimer);
|
|
186
204
|
this.reconnectTimer = null;
|
|
187
205
|
}
|
|
206
|
+
// Clear reconnect buffer timer (but keep message queue for reconnection)
|
|
207
|
+
if (this.reconnectBufferTimer) {
|
|
208
|
+
clearTimeout(this.reconnectBufferTimer);
|
|
209
|
+
this.reconnectBufferTimer = null;
|
|
210
|
+
}
|
|
188
211
|
// Clean up WebSocket
|
|
189
212
|
if (this.ws) {
|
|
190
213
|
// Remove all event listeners
|
|
@@ -282,6 +305,24 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
282
305
|
// Mark as ready after init
|
|
283
306
|
this.state.ready = true;
|
|
284
307
|
this.emit("ready");
|
|
308
|
+
// Start 10-second buffer period after reconnection
|
|
309
|
+
if (this.isBuffering) {
|
|
310
|
+
this.log("[MessageQueue] Reconnected, starting 10s buffer period before flushing queue");
|
|
311
|
+
// Clear any existing buffer timer
|
|
312
|
+
if (this.reconnectBufferTimer) {
|
|
313
|
+
clearTimeout(this.reconnectBufferTimer);
|
|
314
|
+
}
|
|
315
|
+
this.reconnectBufferTimer = setTimeout(() => {
|
|
316
|
+
this.reconnectBufferTimer = null;
|
|
317
|
+
this.messageQueue.flush((msg) => {
|
|
318
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
319
|
+
this.ws.send(JSON.stringify(msg));
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
this.isBuffering = false;
|
|
323
|
+
this.log("[MessageQueue] Buffer period ended, resumed direct sending");
|
|
324
|
+
}, 10000);
|
|
325
|
+
}
|
|
285
326
|
// Start heartbeat
|
|
286
327
|
this.startHeartbeat();
|
|
287
328
|
}
|
|
@@ -321,6 +362,7 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
321
362
|
try {
|
|
322
363
|
const messageStr = data.toString();
|
|
323
364
|
console.log(`[WS-RECV] Raw message frame, size: ${messageStr.length} characters`);
|
|
365
|
+
console.log(`[WS-RECV] Full message JSON: ${messageStr}`);
|
|
324
366
|
const parsed = JSON.parse(messageStr);
|
|
325
367
|
// 提取并打印消息内容(只显示 text,data 只打印提示)
|
|
326
368
|
const parts = parsed.params?.message?.parts;
|
|
@@ -394,6 +436,27 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
394
436
|
taskId: a2aRequest.params?.id, // 新的 taskId(点击推送时生成)
|
|
395
437
|
});
|
|
396
438
|
}
|
|
439
|
+
else if (item.header?.namespace === "AgentEvent" && item.header?.name === "ClawSelfEvolutionState") {
|
|
440
|
+
console.log("[XY] ClawSelfEvolutionState event detected, emitting self-evolution-event");
|
|
441
|
+
this.emit("self-evolution-event", {
|
|
442
|
+
event: item,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
else if (item.header?.namespace === "AgentEvent" && item.header?.name === "ClawSelfEvolutionStateGet") {
|
|
446
|
+
console.log("[XY] ClawSelfEvolutionStateGet event detected, emitting self-evolution-state-get-event");
|
|
447
|
+
this.emit("self-evolution-state-get-event", {
|
|
448
|
+
event: item,
|
|
449
|
+
sessionId: sessionId,
|
|
450
|
+
taskId: a2aRequest.params?.id,
|
|
451
|
+
messageId: a2aRequest.id,
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
else if (item.header?.namespace === "LoginTokenEvent" && item.header?.name === "ClawAutoLogin") {
|
|
455
|
+
console.log("[XY] LoginTokenEvent.ClawAutoLogin detected, emitting login-token-event");
|
|
456
|
+
this.emit("login-token-event", {
|
|
457
|
+
event: item,
|
|
458
|
+
});
|
|
459
|
+
}
|
|
397
460
|
}
|
|
398
461
|
}
|
|
399
462
|
return;
|
|
@@ -448,6 +511,12 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
448
511
|
taskId: inboundMsg.taskId || a2aRequest.params?.id,
|
|
449
512
|
});
|
|
450
513
|
}
|
|
514
|
+
else if (item.header?.namespace === "LoginTokenEvent" && item.header?.name === "ClawAutoLogin") {
|
|
515
|
+
console.log("[XY] LoginTokenEvent.ClawAutoLogin detected (wrapped format), emitting login-token-event");
|
|
516
|
+
this.emit("login-token-event", {
|
|
517
|
+
event: item,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
451
520
|
}
|
|
452
521
|
}
|
|
453
522
|
}
|
|
@@ -482,6 +551,8 @@ export class XYWebSocketManager extends EventEmitter {
|
|
|
482
551
|
}
|
|
483
552
|
this.state.connected = false;
|
|
484
553
|
this.state.ready = false;
|
|
554
|
+
// Start buffering messages during disconnection
|
|
555
|
+
this.isBuffering = true;
|
|
485
556
|
this.emit("disconnected");
|
|
486
557
|
// Clean up
|
|
487
558
|
if (this.heartbeat) {
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ynhcj/xiaoyi-channel",
|
|
3
|
-
"version": "0.0.72-
|
|
3
|
+
"version": "0.0.72-next",
|
|
4
4
|
"description": "OpenClaw Xiaoyi Channel plugin - Xiaoyi A2A protocol integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"openclaw.plugin.json"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build": "tsc"
|
|
19
|
+
"build": "node ./node_modules/typescript/bin/tsc"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|
|
22
22
|
"openclaw",
|