claw-subagent-service 0.0.64 → 0.0.65

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.64",
3
+ "version": "0.0.65",
4
4
  "description": "虾说智能助手",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -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
  }
@@ -62,15 +62,15 @@ class DashboardReporter {
62
62
  start(getMacAddress) {
63
63
  const interval = 30000; // 30秒
64
64
  this.log?.info(`[DashboardReporter] 启动仪表盘上报定时器,间隔: ${interval}ms`);
65
-
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
  }
@@ -132,7 +132,7 @@ class DashboardReporter {
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 isFirstChunk = true;
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
- // 策略:每 30 个字符或遇到句末标点发送一次片段
230
- if (buffer.length >= 30 || /[。!?.!?\n]$/.test(delta)) {
231
- await this._sendStreamChunk(fromUserId, targetId, conversationType, buffer, streamId, isFirstChunk, false);
232
- isFirstChunk = false;
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
- await this._sendStreamChunk(fromUserId, targetId, conversationType, buffer, streamId, isFirstChunk, true);
237
+ seq += 1;
238
+ await this._sendStreamChunk(fromUserId, targetId, conversationType, buffer, streamId, seq === 1, true, seq);
241
239
  hasSentChunk = true;
242
- } else if (!isFirstChunk) {
240
+ } else if (hasSentChunk) {
243
241
  // 已经发送过内容,单独发送结束标记
244
- await this._sendStreamChunk(fromUserId, targetId, conversationType, '', streamId, false, true);
245
- hasSentChunk = true;
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, isFirstChunk, true);
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
- if (!this.isStreamingEnabled) return;
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