claw-subagent-service 0.0.64 → 0.0.66
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
|
@@ -13,11 +13,11 @@ class HeartbeatManager {
|
|
|
13
13
|
|
|
14
14
|
start(getMacAddress, getOpenClawStatus) {
|
|
15
15
|
const interval = (this.config.heartbeatInterval || 20) * 1000;
|
|
16
|
-
this.log?.info(`[HeartbeatManager] 启动心跳定时器,间隔: ${interval}ms`);
|
|
17
|
-
|
|
16
|
+
// this.log?.info(`[HeartbeatManager] 启动心跳定时器,间隔: ${interval}ms`);
|
|
17
|
+
|
|
18
18
|
this.timer = setInterval(async () => {
|
|
19
19
|
if (!this.rongcloudClient?.isConnected) return;
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
try {
|
|
22
22
|
const mac = getMacAddress();
|
|
23
23
|
const status = await getOpenClawStatus(this.config.openclawPort || 18789);
|
|
@@ -31,7 +31,7 @@ class HeartbeatManager {
|
|
|
31
31
|
}
|
|
32
32
|
);
|
|
33
33
|
if (sent) {
|
|
34
|
-
this.log?.info('[HeartbeatManager] 心跳已发送');
|
|
34
|
+
// this.log?.info('[HeartbeatManager] 心跳已发送');
|
|
35
35
|
} else {
|
|
36
36
|
this.log?.warn('[HeartbeatManager] 心跳发送失败');
|
|
37
37
|
}
|
|
@@ -61,16 +61,16 @@ class DashboardReporter {
|
|
|
61
61
|
|
|
62
62
|
start(getMacAddress) {
|
|
63
63
|
const interval = 30000; // 30秒
|
|
64
|
-
this.log?.info(`[DashboardReporter] 启动仪表盘上报定时器,间隔: ${interval}ms`);
|
|
65
|
-
|
|
64
|
+
// this.log?.info(`[DashboardReporter] 启动仪表盘上报定时器,间隔: ${interval}ms`);
|
|
65
|
+
|
|
66
66
|
this.timer = setInterval(async () => {
|
|
67
67
|
if (!this.rongcloudClient?.isConnected) return;
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
try {
|
|
70
70
|
const data = await collectDashboardData();
|
|
71
71
|
const timestamp = data.diagnostics?.generatedAt || new Date().toISOString();
|
|
72
72
|
const mac = getMacAddress();
|
|
73
|
-
|
|
73
|
+
|
|
74
74
|
// 拆分为 6 条消息发送
|
|
75
75
|
await this.sendChunk(RongyunMessageTypeEnum.DASHBOARD_SESSIONS, {
|
|
76
76
|
mac_address: mac,
|
|
@@ -78,21 +78,21 @@ class DashboardReporter {
|
|
|
78
78
|
sessionStatuses: data.sessionStatuses,
|
|
79
79
|
timestamp,
|
|
80
80
|
}, 1000);
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
await this.sendChunk(RongyunMessageTypeEnum.DASHBOARD_JOBS, {
|
|
83
83
|
mac_address: mac,
|
|
84
84
|
cronJobs: data.cronJobs,
|
|
85
85
|
approvals: data.approvals,
|
|
86
86
|
timestamp,
|
|
87
87
|
}, 1000);
|
|
88
|
-
|
|
88
|
+
|
|
89
89
|
await this.sendChunk(RongyunMessageTypeEnum.DASHBOARD_PROJECTS, {
|
|
90
90
|
mac_address: mac,
|
|
91
91
|
projects: data.projects,
|
|
92
92
|
tasks: data.tasks,
|
|
93
93
|
timestamp,
|
|
94
94
|
}, 1000);
|
|
95
|
-
|
|
95
|
+
|
|
96
96
|
await this.sendChunk(RongyunMessageTypeEnum.DASHBOARD_SUMMARIES, {
|
|
97
97
|
mac_address: mac,
|
|
98
98
|
projectSummaries: data.projectSummaries,
|
|
@@ -101,20 +101,20 @@ class DashboardReporter {
|
|
|
101
101
|
diagnostics: data.diagnostics,
|
|
102
102
|
timestamp,
|
|
103
103
|
}, 1000);
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
await this.sendChunk(RongyunMessageTypeEnum.DASHBOARD_SESSIONS_CONTEXTS, {
|
|
106
106
|
mac_address: mac,
|
|
107
107
|
sessionsContexts: (data.sessionsContexts || []).slice(0, 50),
|
|
108
108
|
timestamp,
|
|
109
109
|
}, 1000);
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
await this.sendChunk(RongyunMessageTypeEnum.DASHBOARD_USAGE_EVENTS, {
|
|
112
112
|
mac_address: mac,
|
|
113
113
|
usageEvents: (data.usageEvents || []).slice(-100),
|
|
114
114
|
timestamp,
|
|
115
115
|
}, 0);
|
|
116
|
-
|
|
117
|
-
this.log?.info('[DashboardReporter] 所有数据块发送完成');
|
|
116
|
+
|
|
117
|
+
// this.log?.info('[DashboardReporter] 所有数据块发送完成');
|
|
118
118
|
} catch (err) {
|
|
119
119
|
this.log?.error(`[DashboardReporter] 上报异常: ${err.message}`);
|
|
120
120
|
}
|
|
@@ -125,14 +125,14 @@ class DashboardReporter {
|
|
|
125
125
|
try {
|
|
126
126
|
const sent = await this.messageSender.sendProtocolMessage(msgType, data);
|
|
127
127
|
if (sent) {
|
|
128
|
-
this.log?.info(`[DashboardReporter] ${msgType} 发送成功`);
|
|
128
|
+
// this.log?.info(`[DashboardReporter] ${msgType} 发送成功`);
|
|
129
129
|
} else {
|
|
130
130
|
this.log?.warn(`[DashboardReporter] ${msgType} 发送失败`);
|
|
131
131
|
}
|
|
132
132
|
} catch (err) {
|
|
133
133
|
this.log?.error(`[DashboardReporter] ${msgType} 发送异常: ${err.message}`);
|
|
134
134
|
}
|
|
135
|
-
|
|
135
|
+
|
|
136
136
|
if (delayMs > 0) {
|
|
137
137
|
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
138
138
|
}
|
|
@@ -22,7 +22,7 @@ class RongyunMessageSender {
|
|
|
22
22
|
buildMessage(msgType, content, requestId) {
|
|
23
23
|
const mac = getMacAddress();
|
|
24
24
|
const secret = generateSecret(mac, this.config.secretKey || 'secret_key');
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
return {
|
|
27
27
|
msg_type: msgType,
|
|
28
28
|
source_im_id: this.config.accountId || '',
|
|
@@ -46,8 +46,8 @@ class RongyunMessageSender {
|
|
|
46
46
|
|
|
47
47
|
try {
|
|
48
48
|
const messagePayload = this.buildMessage(msgType, content, requestId);
|
|
49
|
-
|
|
50
|
-
this.log?.info(`[RongyunMessageSender] 发送协议消息 -> ${this.serverImId}, type=${msgType}`);
|
|
49
|
+
|
|
50
|
+
// this.log?.info(`[RongyunMessageSender] 发送协议消息 -> ${this.serverImId}, type=${msgType}`);
|
|
51
51
|
|
|
52
52
|
const result = await this.rongcloudClient.sendMessage(
|
|
53
53
|
this.serverImId,
|
|
@@ -56,7 +56,7 @@ class RongyunMessageSender {
|
|
|
56
56
|
);
|
|
57
57
|
|
|
58
58
|
if (result) {
|
|
59
|
-
this.log?.info(`[RongyunMessageSender] ${msgType} 发送成功`);
|
|
59
|
+
// this.log?.info(`[RongyunMessageSender] ${msgType} 发送成功`);
|
|
60
60
|
} else {
|
|
61
61
|
this.log?.warn(`[RongyunMessageSender] ${msgType} 发送失败`);
|
|
62
62
|
}
|
|
@@ -208,7 +208,7 @@ class MessageHandler {
|
|
|
208
208
|
async handleNormalMessageStream(msg) {
|
|
209
209
|
const targetId = this.getReplyTarget(msg);
|
|
210
210
|
const streamId = `${Date.now()}-${Math.random().toString(36).substring(2, 10)}`;
|
|
211
|
-
let
|
|
211
|
+
let seq = 0;
|
|
212
212
|
let buffer = '';
|
|
213
213
|
const fromUserId = this.config.accountId;
|
|
214
214
|
const conversationType = msg.conversationType;
|
|
@@ -226,26 +226,24 @@ class MessageHandler {
|
|
|
226
226
|
msg.senderUserId,
|
|
227
227
|
async (delta) => {
|
|
228
228
|
buffer += delta;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
hasSentChunk = true;
|
|
234
|
-
buffer = '';
|
|
235
|
-
}
|
|
229
|
+
seq += 1;
|
|
230
|
+
this.log?.info(`[MessageHandler] onDelta: seq=${seq}, delta_len=${delta.length}, buffer_len=${buffer.length}`);
|
|
231
|
+
await this._sendStreamChunk(fromUserId, targetId, conversationType, buffer, streamId, seq === 1, false, seq);
|
|
232
|
+
hasSentChunk = true;
|
|
236
233
|
},
|
|
237
234
|
async (fullText) => {
|
|
238
|
-
|
|
235
|
+
this.log?.info(`[MessageHandler] onDone 触发, fullText.length=${fullText.length}, buffer.length=${buffer.length}, hasSentChunk=${hasSentChunk}`);
|
|
239
236
|
if (buffer.trim()) {
|
|
240
|
-
|
|
237
|
+
seq += 1;
|
|
238
|
+
await this._sendStreamChunk(fromUserId, targetId, conversationType, buffer, streamId, seq === 1, true, seq);
|
|
241
239
|
hasSentChunk = true;
|
|
242
|
-
} else if (
|
|
240
|
+
} else if (hasSentChunk) {
|
|
243
241
|
// 已经发送过内容,单独发送结束标记
|
|
244
|
-
|
|
245
|
-
|
|
242
|
+
seq += 1;
|
|
243
|
+
await this._sendStreamChunk(fromUserId, targetId, conversationType, buffer, streamId, false, true, seq);
|
|
246
244
|
} else {
|
|
247
245
|
// 完全没有收到内容,发送错误提示
|
|
248
|
-
await this._sendStreamChunk(fromUserId, targetId, conversationType, '抱歉,AI 暂时没有回复内容。', streamId, true, true);
|
|
246
|
+
await this._sendStreamChunk(fromUserId, targetId, conversationType, '抱歉,AI 暂时没有回复内容。', streamId, true, true, 1);
|
|
249
247
|
hasSentChunk = true;
|
|
250
248
|
}
|
|
251
249
|
|
|
@@ -258,7 +256,7 @@ class MessageHandler {
|
|
|
258
256
|
);
|
|
259
257
|
} catch (err) {
|
|
260
258
|
this.log?.error(`[MessageHandler] 流式处理错误: ${err.message}`);
|
|
261
|
-
await this._sendStreamChunk(fromUserId, targetId, conversationType, '抱歉,AI 响应出现错误,请稍后重试。', streamId,
|
|
259
|
+
await this._sendStreamChunk(fromUserId, targetId, conversationType, '抱歉,AI 响应出现错误,请稍后重试。', streamId, true, true, 1);
|
|
262
260
|
throw err;
|
|
263
261
|
}
|
|
264
262
|
}
|
|
@@ -289,10 +287,14 @@ class MessageHandler {
|
|
|
289
287
|
/**
|
|
290
288
|
* 发送流式消息片段(通过 Python 后端代理)
|
|
291
289
|
*/
|
|
292
|
-
async _sendStreamChunk(fromUserId, targetId, conversationType, content, streamId, isFirstChunk, isLastChunk) {
|
|
293
|
-
|
|
290
|
+
async _sendStreamChunk(fromUserId, targetId, conversationType, content, streamId, isFirstChunk, isLastChunk, seq = 1) {
|
|
291
|
+
this.log?.info(`[MessageHandler] _sendStreamChunk ENTRY: target=${targetId}, streamId=${streamId}, seq=${seq}, first=${isFirstChunk}, last=${isLastChunk}, content_len=${content?.length || 0}`);
|
|
292
|
+
if (!this.isStreamingEnabled) {
|
|
293
|
+
this.log?.warn('[MessageHandler] _sendStreamChunk skipped: isStreamingEnabled=false');
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
294
296
|
try {
|
|
295
|
-
await axios.post(
|
|
297
|
+
const resp = await axios.post(
|
|
296
298
|
`${this.config.apiBaseUrl}/im/api/proxy/stream/publish`,
|
|
297
299
|
{
|
|
298
300
|
fromUserId,
|
|
@@ -301,14 +303,16 @@ class MessageHandler {
|
|
|
301
303
|
streamId,
|
|
302
304
|
isFirstChunk,
|
|
303
305
|
isLastChunk,
|
|
304
|
-
conversationType
|
|
306
|
+
conversationType,
|
|
307
|
+
seq
|
|
305
308
|
},
|
|
306
309
|
{ timeout: 10000 }
|
|
307
310
|
);
|
|
311
|
+
this.log?.info(`[MessageHandler] _sendStreamChunk 成功: status=${resp.status}, seq=${seq}`);
|
|
308
312
|
} catch (err) {
|
|
309
313
|
const url = `${this.config.apiBaseUrl}/im/api/proxy/stream/publish`;
|
|
310
314
|
const status = err.response?.status;
|
|
311
|
-
this.log?.warn(`[MessageHandler] 发送流式消息失败: ${err.message}, url=${url}, status=${status || 'N/A'}`);
|
|
315
|
+
this.log?.warn(`[MessageHandler] 发送流式消息失败: ${err.message}, url=${url}, status=${status || 'N/A'}, seq=${seq}`);
|
|
312
316
|
}
|
|
313
317
|
}
|
|
314
318
|
|
|
@@ -438,8 +438,13 @@ class OpenClawClient {
|
|
|
438
438
|
|
|
439
439
|
try {
|
|
440
440
|
const data = JSON.parse(dataStr);
|
|
441
|
-
|
|
442
|
-
|
|
441
|
+
// 尝试多个可能的内容字段,兼容不同版本 OpenClaw
|
|
442
|
+
const delta = data.choices?.[0]?.delta?.content
|
|
443
|
+
?? data.choices?.[0]?.message?.content
|
|
444
|
+
?? data.choices?.[0]?.text
|
|
445
|
+
?? data.content
|
|
446
|
+
?? data.delta;
|
|
447
|
+
if (typeof delta === 'string' && delta) {
|
|
443
448
|
fullText += delta;
|
|
444
449
|
try {
|
|
445
450
|
await onDelta?.(delta);
|
|
@@ -447,6 +452,9 @@ class OpenClawClient {
|
|
|
447
452
|
reject(err);
|
|
448
453
|
return;
|
|
449
454
|
}
|
|
455
|
+
} else {
|
|
456
|
+
// 调试:打印未识别的 SSE 数据结构
|
|
457
|
+
this.log?.info(`[OpenClawClient] SSE 原始数据(无delta): ${JSON.stringify(data).substring(0, 200)}`);
|
|
450
458
|
}
|
|
451
459
|
} catch {
|
|
452
460
|
// 忽略无法解析的 JSON 行
|
|
@@ -226,7 +226,7 @@ class RongCloudClient {
|
|
|
226
226
|
? (RongIMLib.ConversationType?.GROUP || ConversationType.GROUP)
|
|
227
227
|
: (RongIMLib.ConversationType?.PRIVATE || ConversationType.PRIVATE);
|
|
228
228
|
|
|
229
|
-
this.log?.info(`[RongCloudClient] 发送消息 -> ${targetId} (Type: ${convType}): ${content.substring(0, 50)}`);
|
|
229
|
+
// this.log?.info(`[RongCloudClient] 发送消息 -> ${targetId} (Type: ${convType}): ${content.substring(0, 50)}`);
|
|
230
230
|
|
|
231
231
|
const result = await RongIMLib.sendTextMessage(
|
|
232
232
|
{ conversationType: convType, targetId },
|
|
@@ -237,7 +237,7 @@ class RongCloudClient {
|
|
|
237
237
|
|
|
238
238
|
if (result.code === 0 || result.code === 200) {
|
|
239
239
|
const sentUId = result.data?.messageUId;
|
|
240
|
-
this.log?.info(`[RongCloudClient] 发送成功, messageUId: ${sentUId}`);
|
|
240
|
+
// this.log?.info(`[RongCloudClient] 发送成功, messageUId: ${sentUId}`);
|
|
241
241
|
// 将发送成功的 messageUId 加入短期缓存,用于过滤 SDK 回传的自己消息
|
|
242
242
|
if (sentUId) {
|
|
243
243
|
this.sentMessageUIds.add(sentUId);
|