@ynhcj/xiaoyi 2.2.5 → 2.2.7
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/channel.js +60 -0
- package/dist/config-schema.d.ts +1 -1
- package/dist/runtime.d.ts +45 -0
- package/dist/runtime.js +97 -0
- package/package.json +1 -1
package/dist/channel.js
CHANGED
|
@@ -319,6 +319,49 @@ exports.xiaoyiPlugin = {
|
|
|
319
319
|
const taskId = runtime.getTaskIdForSession(message.sessionId) || `task_${Date.now()}`;
|
|
320
320
|
const startTime = Date.now();
|
|
321
321
|
let accumulatedText = "";
|
|
322
|
+
// ==================== START TIMEOUT PROTECTION ====================
|
|
323
|
+
// Start 60-second timeout timer
|
|
324
|
+
const timeoutConfig = runtime.getTimeoutConfig();
|
|
325
|
+
console.log(`[TIMEOUT] Starting ${timeoutConfig.duration}ms timeout protection for session ${message.sessionId}`);
|
|
326
|
+
runtime.setTimeoutForSession(message.sessionId, async () => {
|
|
327
|
+
// Timeout callback - send timeout message to user
|
|
328
|
+
const elapsed = Date.now() - startTime;
|
|
329
|
+
console.log("\n" + "=".repeat(60));
|
|
330
|
+
console.log(`[TIMEOUT] Timeout triggered for session ${message.sessionId}`);
|
|
331
|
+
console.log(` Elapsed: ${elapsed}ms`);
|
|
332
|
+
console.log(` Task ID: ${taskId}`);
|
|
333
|
+
console.log("=".repeat(60) + "\n");
|
|
334
|
+
const conn = runtime.getConnection();
|
|
335
|
+
if (conn) {
|
|
336
|
+
const timeoutResponse = {
|
|
337
|
+
sessionId: message.sessionId,
|
|
338
|
+
messageId: `timeout_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
339
|
+
timestamp: Date.now(),
|
|
340
|
+
agentId: resolvedAccount.config.agentId,
|
|
341
|
+
sender: {
|
|
342
|
+
id: resolvedAccount.config.agentId,
|
|
343
|
+
name: "OpenClaw Agent",
|
|
344
|
+
type: "agent",
|
|
345
|
+
},
|
|
346
|
+
content: {
|
|
347
|
+
type: "text",
|
|
348
|
+
text: timeoutConfig.message,
|
|
349
|
+
},
|
|
350
|
+
status: "success",
|
|
351
|
+
};
|
|
352
|
+
try {
|
|
353
|
+
await conn.sendResponse(timeoutResponse, taskId, message.sessionId, true, false);
|
|
354
|
+
console.log(`[TIMEOUT] Timeout message sent successfully to session ${message.sessionId}\n`);
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
console.error(`[TIMEOUT] Failed to send timeout message:`, error);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
console.error(`[TIMEOUT] Connection not available, cannot send timeout message\n`);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
// ==================== END TIMEOUT PROTECTION ====================
|
|
322
365
|
await pluginRuntime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
323
366
|
ctx: msgContext,
|
|
324
367
|
cfg: config,
|
|
@@ -327,6 +370,17 @@ exports.xiaoyiPlugin = {
|
|
|
327
370
|
const elapsed = Date.now() - startTime;
|
|
328
371
|
const completeText = payload.text || "";
|
|
329
372
|
accumulatedText = completeText;
|
|
373
|
+
// ==================== CHECK TIMEOUT ====================
|
|
374
|
+
// If timeout already sent, discard this response
|
|
375
|
+
if (runtime.isSessionTimeout(message.sessionId)) {
|
|
376
|
+
console.log("\n" + "=".repeat(60));
|
|
377
|
+
console.log(`[TIMEOUT] Response received AFTER timeout`);
|
|
378
|
+
console.log(` Session: ${message.sessionId}`);
|
|
379
|
+
console.log(` Elapsed: ${elapsed}ms`);
|
|
380
|
+
console.log(` Action: DISCARDING (timeout message already sent)`);
|
|
381
|
+
console.log("=".repeat(60) + "\n");
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
330
384
|
console.log("\n" + "-".repeat(60));
|
|
331
385
|
console.log(`XiaoYi: [DELIVER] AI response received`);
|
|
332
386
|
console.log(` Elapsed: ${elapsed}ms`);
|
|
@@ -358,6 +412,8 @@ exports.xiaoyiPlugin = {
|
|
|
358
412
|
else {
|
|
359
413
|
console.error(`✗ XiaoYi: Connection not available\n`);
|
|
360
414
|
}
|
|
415
|
+
// Clear timeout as response was sent successfully
|
|
416
|
+
runtime.markSessionCompleted(message.sessionId);
|
|
361
417
|
},
|
|
362
418
|
onIdle: async () => {
|
|
363
419
|
const elapsed = Date.now() - startTime;
|
|
@@ -366,6 +422,8 @@ exports.xiaoyiPlugin = {
|
|
|
366
422
|
console.log(` Total time: ${elapsed}ms`);
|
|
367
423
|
console.log(` Final length: ${accumulatedText.length} chars`);
|
|
368
424
|
console.log("=".repeat(60) + "\n");
|
|
425
|
+
// Clear timeout on completion
|
|
426
|
+
runtime.markSessionCompleted(message.sessionId);
|
|
369
427
|
},
|
|
370
428
|
},
|
|
371
429
|
replyOptions: undefined,
|
|
@@ -374,6 +432,8 @@ exports.xiaoyiPlugin = {
|
|
|
374
432
|
}
|
|
375
433
|
catch (error) {
|
|
376
434
|
console.error("XiaoYi: [ERROR] Error dispatching message:", error);
|
|
435
|
+
// Clear timeout on error
|
|
436
|
+
runtime.clearSessionTimeout(message.sessionId);
|
|
377
437
|
}
|
|
378
438
|
});
|
|
379
439
|
// Setup cancel handler
|
package/dist/config-schema.d.ts
CHANGED
|
@@ -33,8 +33,8 @@ export declare const XiaoYiConfigSchema: z.ZodObject<{
|
|
|
33
33
|
agentId?: string | undefined;
|
|
34
34
|
accounts?: Record<string, unknown> | undefined;
|
|
35
35
|
}, {
|
|
36
|
-
name?: string | undefined;
|
|
37
36
|
enabled?: boolean | undefined;
|
|
37
|
+
name?: string | undefined;
|
|
38
38
|
wsUrl?: string | undefined;
|
|
39
39
|
ak?: string | undefined;
|
|
40
40
|
sk?: string | undefined;
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { XiaoYiWebSocketManager } from "./websocket";
|
|
2
2
|
import { XiaoYiChannelConfig } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Timeout configuration
|
|
5
|
+
*/
|
|
6
|
+
export interface TimeoutConfig {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
duration: number;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
3
11
|
/**
|
|
4
12
|
* Runtime state for XiaoYi channel
|
|
5
13
|
* Manages single WebSocket connection (single account mode)
|
|
@@ -10,6 +18,9 @@ export declare class XiaoYiRuntime {
|
|
|
10
18
|
private config;
|
|
11
19
|
private sessionToTaskIdMap;
|
|
12
20
|
private instanceId;
|
|
21
|
+
private sessionTimeoutMap;
|
|
22
|
+
private sessionTimeoutSent;
|
|
23
|
+
private timeoutConfig;
|
|
13
24
|
constructor();
|
|
14
25
|
getInstanceId(): string;
|
|
15
26
|
/**
|
|
@@ -28,6 +39,40 @@ export declare class XiaoYiRuntime {
|
|
|
28
39
|
* Stop connection
|
|
29
40
|
*/
|
|
30
41
|
stop(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Set timeout configuration
|
|
44
|
+
*/
|
|
45
|
+
setTimeoutConfig(config: Partial<TimeoutConfig>): void;
|
|
46
|
+
/**
|
|
47
|
+
* Get timeout configuration
|
|
48
|
+
*/
|
|
49
|
+
getTimeoutConfig(): TimeoutConfig;
|
|
50
|
+
/**
|
|
51
|
+
* Set timeout for a session
|
|
52
|
+
* @param sessionId - Session ID
|
|
53
|
+
* @param callback - Function to call when timeout occurs
|
|
54
|
+
* @returns The timeout ID (for cancellation)
|
|
55
|
+
*/
|
|
56
|
+
setTimeoutForSession(sessionId: string, callback: () => void): NodeJS.Timeout | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Clear timeout for a session
|
|
59
|
+
* @param sessionId - Session ID
|
|
60
|
+
*/
|
|
61
|
+
clearSessionTimeout(sessionId: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Check if timeout has been sent for a session
|
|
64
|
+
* @param sessionId - Session ID
|
|
65
|
+
*/
|
|
66
|
+
isSessionTimeout(sessionId: string): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Mark session as completed (clear timeout and timeout flag)
|
|
69
|
+
* @param sessionId - Session ID
|
|
70
|
+
*/
|
|
71
|
+
markSessionCompleted(sessionId: string): void;
|
|
72
|
+
/**
|
|
73
|
+
* Clear all timeouts
|
|
74
|
+
*/
|
|
75
|
+
clearAllTimeouts(): void;
|
|
31
76
|
/**
|
|
32
77
|
* Get WebSocket manager
|
|
33
78
|
*/
|
package/dist/runtime.js
CHANGED
|
@@ -4,6 +4,14 @@ exports.XiaoYiRuntime = void 0;
|
|
|
4
4
|
exports.getXiaoYiRuntime = getXiaoYiRuntime;
|
|
5
5
|
exports.setXiaoYiRuntime = setXiaoYiRuntime;
|
|
6
6
|
const websocket_1 = require("./websocket");
|
|
7
|
+
/**
|
|
8
|
+
* Default timeout configuration
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_TIMEOUT_CONFIG = {
|
|
11
|
+
enabled: true,
|
|
12
|
+
duration: 60000, // 60 seconds
|
|
13
|
+
message: "任务还在处理中,请稍后回来查看",
|
|
14
|
+
};
|
|
7
15
|
/**
|
|
8
16
|
* Runtime state for XiaoYi channel
|
|
9
17
|
* Manages single WebSocket connection (single account mode)
|
|
@@ -14,6 +22,10 @@ class XiaoYiRuntime {
|
|
|
14
22
|
this.pluginRuntime = null; // Store PluginRuntime from OpenClaw
|
|
15
23
|
this.config = null;
|
|
16
24
|
this.sessionToTaskIdMap = new Map(); // Map sessionId to taskId
|
|
25
|
+
// Timeout management
|
|
26
|
+
this.sessionTimeoutMap = new Map();
|
|
27
|
+
this.sessionTimeoutSent = new Set();
|
|
28
|
+
this.timeoutConfig = DEFAULT_TIMEOUT_CONFIG;
|
|
17
29
|
this.instanceId = `runtime_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
18
30
|
console.log(`XiaoYi: Created new runtime instance: ${this.instanceId}`);
|
|
19
31
|
}
|
|
@@ -73,6 +85,91 @@ class XiaoYiRuntime {
|
|
|
73
85
|
}
|
|
74
86
|
// Clear session mappings
|
|
75
87
|
this.sessionToTaskIdMap.clear();
|
|
88
|
+
// Clear all timeouts
|
|
89
|
+
this.clearAllTimeouts();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Set timeout configuration
|
|
93
|
+
*/
|
|
94
|
+
setTimeoutConfig(config) {
|
|
95
|
+
this.timeoutConfig = { ...this.timeoutConfig, ...config };
|
|
96
|
+
console.log(`XiaoYi: Timeout config updated:`, this.timeoutConfig);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get timeout configuration
|
|
100
|
+
*/
|
|
101
|
+
getTimeoutConfig() {
|
|
102
|
+
return { ...this.timeoutConfig };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Set timeout for a session
|
|
106
|
+
* @param sessionId - Session ID
|
|
107
|
+
* @param callback - Function to call when timeout occurs
|
|
108
|
+
* @returns The timeout ID (for cancellation)
|
|
109
|
+
*/
|
|
110
|
+
setTimeoutForSession(sessionId, callback) {
|
|
111
|
+
if (!this.timeoutConfig.enabled) {
|
|
112
|
+
console.log(`[TIMEOUT] Timeout disabled, skipping for session ${sessionId}`);
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
// Clear existing timeout AND timeout flag if any (reuse session scenario)
|
|
116
|
+
const hadExistingTimeout = this.sessionTimeoutMap.has(sessionId);
|
|
117
|
+
const hadSentTimeout = this.sessionTimeoutSent.has(sessionId);
|
|
118
|
+
this.clearSessionTimeout(sessionId);
|
|
119
|
+
// Also clear the timeout sent flag to allow this session to timeout again
|
|
120
|
+
if (hadSentTimeout) {
|
|
121
|
+
this.sessionTimeoutSent.delete(sessionId);
|
|
122
|
+
console.log(`[TIMEOUT] Previous timeout flag cleared for session ${sessionId} (session reuse)`);
|
|
123
|
+
}
|
|
124
|
+
const timeoutId = setTimeout(() => {
|
|
125
|
+
console.log(`[TIMEOUT] Timeout triggered for session ${sessionId}`);
|
|
126
|
+
this.sessionTimeoutMap.delete(sessionId);
|
|
127
|
+
this.sessionTimeoutSent.add(sessionId);
|
|
128
|
+
callback();
|
|
129
|
+
}, this.timeoutConfig.duration);
|
|
130
|
+
this.sessionTimeoutMap.set(sessionId, timeoutId);
|
|
131
|
+
const logSuffix = hadExistingTimeout ? " (replacing existing timeout)" : "";
|
|
132
|
+
console.log(`[TIMEOUT] ${this.timeoutConfig.duration}ms timeout started for session ${sessionId}${logSuffix}`);
|
|
133
|
+
return timeoutId;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Clear timeout for a session
|
|
137
|
+
* @param sessionId - Session ID
|
|
138
|
+
*/
|
|
139
|
+
clearSessionTimeout(sessionId) {
|
|
140
|
+
const timeoutId = this.sessionTimeoutMap.get(sessionId);
|
|
141
|
+
if (timeoutId) {
|
|
142
|
+
clearTimeout(timeoutId);
|
|
143
|
+
this.sessionTimeoutMap.delete(sessionId);
|
|
144
|
+
console.log(`[TIMEOUT] Timeout cleared for session ${sessionId}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Check if timeout has been sent for a session
|
|
149
|
+
* @param sessionId - Session ID
|
|
150
|
+
*/
|
|
151
|
+
isSessionTimeout(sessionId) {
|
|
152
|
+
return this.sessionTimeoutSent.has(sessionId);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Mark session as completed (clear timeout and timeout flag)
|
|
156
|
+
* @param sessionId - Session ID
|
|
157
|
+
*/
|
|
158
|
+
markSessionCompleted(sessionId) {
|
|
159
|
+
this.clearSessionTimeout(sessionId);
|
|
160
|
+
this.sessionTimeoutSent.delete(sessionId);
|
|
161
|
+
console.log(`[TIMEOUT] Session ${sessionId} marked as completed`);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Clear all timeouts
|
|
165
|
+
*/
|
|
166
|
+
clearAllTimeouts() {
|
|
167
|
+
for (const [sessionId, timeoutId] of this.sessionTimeoutMap.entries()) {
|
|
168
|
+
clearTimeout(timeoutId);
|
|
169
|
+
}
|
|
170
|
+
this.sessionTimeoutMap.clear();
|
|
171
|
+
this.sessionTimeoutSent.clear();
|
|
172
|
+
console.log("[TIMEOUT] All timeouts cleared");
|
|
76
173
|
}
|
|
77
174
|
/**
|
|
78
175
|
* Get WebSocket manager
|