claw-subagent-service 0.0.153 → 0.0.155
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
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
const { RongyunMessageTypeEnum } = require('./rongyun-message-types');
|
|
11
11
|
const { OpenClawCommandEnum, getCommandName } = require('./openclaw-enum');
|
|
12
12
|
const { executeCommand } = require('./openclaw-control');
|
|
13
|
-
const { createOpencodeSession, deleteOpencodeSession, forwardChatMessage } = require('./opencode-service');
|
|
13
|
+
const { createOpencodeSession, deleteOpencodeSession, forwardChatMessage, getOrCreateGatewaySession } = require('./opencode-service');
|
|
14
14
|
const { ServiceManager } = require('./service-manager');
|
|
15
15
|
const { collectDashboardData } = require('./dashboard-collector');
|
|
16
16
|
const { getOpenClawStatus } = require('./port-checker');
|
|
@@ -19,6 +19,34 @@ const fs = require('fs');
|
|
|
19
19
|
const path = require('path');
|
|
20
20
|
const os = require('os');
|
|
21
21
|
|
|
22
|
+
// 客服会话存储(内存缓存,生产环境建议用 Redis)
|
|
23
|
+
const serviceSessions = new Map();
|
|
24
|
+
|
|
25
|
+
// 客服系统提示词
|
|
26
|
+
const SERVICE_SYSTEM_PROMPT = `你是虾说App的智能客服助手,专门帮助用户解答使用问题。
|
|
27
|
+
|
|
28
|
+
## 核心职责
|
|
29
|
+
1. **解答产品使用问题**:帮助用户了解如何使用虾说App的各项功能
|
|
30
|
+
2. **故障排查**:协助用户解决常见的技术问题
|
|
31
|
+
3. **功能介绍**:介绍App的新功能和更新内容
|
|
32
|
+
|
|
33
|
+
## 常用功能说明
|
|
34
|
+
|
|
35
|
+
| 功能 | 说明 |
|
|
36
|
+
|------|------|
|
|
37
|
+
| 会话 | 与好友进行一对一或群聊 |
|
|
38
|
+
| 通讯录 | 管理好友和群组 |
|
|
39
|
+
| 聊天室 | 加入公开聊天室 |
|
|
40
|
+
| 远程管理 | 管理远程设备 |
|
|
41
|
+
| AI助手 | 使用AI辅助功能 |
|
|
42
|
+
|
|
43
|
+
## 回答原则
|
|
44
|
+
- 礼貌、专业、简洁
|
|
45
|
+
- 如果不知道答案,建议用户联系人工客服
|
|
46
|
+
- 不要透露系统内部信息
|
|
47
|
+
- 使用中文回答
|
|
48
|
+
`;
|
|
49
|
+
|
|
22
50
|
class RongyunMessageHandler {
|
|
23
51
|
constructor(rongcloudClient, config, log) {
|
|
24
52
|
this.rongcloudClient = rongcloudClient;
|
|
@@ -99,6 +127,12 @@ class RongyunMessageHandler {
|
|
|
99
127
|
case RongyunMessageTypeEnum.DEVICE_STATUS_REQUEST:
|
|
100
128
|
await this.handleDeviceStatusRequest(data);
|
|
101
129
|
break;
|
|
130
|
+
case RongyunMessageTypeEnum.CREATE_SERVICE_SESSION:
|
|
131
|
+
await this.handleCreateServiceSession(data);
|
|
132
|
+
break;
|
|
133
|
+
case RongyunMessageTypeEnum.SERVICE_CHAT_MESSAGE:
|
|
134
|
+
await this.handleServiceChatMessage(data);
|
|
135
|
+
break;
|
|
102
136
|
default:
|
|
103
137
|
this.logWarn(`未处理的消息类型: ${msgType}`);
|
|
104
138
|
}
|
|
@@ -461,6 +495,136 @@ class RongyunMessageHandler {
|
|
|
461
495
|
}
|
|
462
496
|
}
|
|
463
497
|
|
|
498
|
+
async handleCreateServiceSession(data) {
|
|
499
|
+
const requestId = data.request_id;
|
|
500
|
+
const userId = data.userId || data.source_im_id;
|
|
501
|
+
const sourceId = data.source_im_id;
|
|
502
|
+
|
|
503
|
+
this.logInfo(`[RongyunMessageHandler] 创建客服会话, userId=${userId}, from=${sourceId}`);
|
|
504
|
+
|
|
505
|
+
try {
|
|
506
|
+
// 创建 OpenCode session 用于客服对话
|
|
507
|
+
const session = await createOpencodeSession(`客服会话-${userId}`);
|
|
508
|
+
const sessionId = session.id || session.session_id;
|
|
509
|
+
|
|
510
|
+
// 存储会话映射关系
|
|
511
|
+
serviceSessions.set(userId, {
|
|
512
|
+
sessionId: sessionId,
|
|
513
|
+
userId: userId,
|
|
514
|
+
createdAt: Date.now(),
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
this.logInfo(`[RongyunMessageHandler] 客服会话创建成功: ${sessionId}`);
|
|
518
|
+
|
|
519
|
+
await this.sendResponse(
|
|
520
|
+
RongyunMessageTypeEnum.SERVICE_SESSION_CREATED,
|
|
521
|
+
{
|
|
522
|
+
status: 'success',
|
|
523
|
+
sessionId: sessionId,
|
|
524
|
+
userId: userId,
|
|
525
|
+
},
|
|
526
|
+
requestId,
|
|
527
|
+
sourceId
|
|
528
|
+
);
|
|
529
|
+
} catch (e) {
|
|
530
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
531
|
+
this.logError(`创建客服会话失败: ${msg}`);
|
|
532
|
+
await this.sendResponse(
|
|
533
|
+
RongyunMessageTypeEnum.SERVICE_SESSION_CREATED,
|
|
534
|
+
{
|
|
535
|
+
status: 'error',
|
|
536
|
+
message: msg,
|
|
537
|
+
},
|
|
538
|
+
requestId,
|
|
539
|
+
sourceId
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
async handleServiceChatMessage(data) {
|
|
545
|
+
const requestId = data.request_id;
|
|
546
|
+
const userId = data.userId || data.source_im_id;
|
|
547
|
+
const sourceId = data.source_im_id;
|
|
548
|
+
const content = data.content || data._raw_content;
|
|
549
|
+
|
|
550
|
+
this.logInfo(`[RongyunMessageHandler] 收到客服消息, userId=${userId}, content=${content?.substring(0, 50)}`);
|
|
551
|
+
|
|
552
|
+
if (!content) {
|
|
553
|
+
this.logWarn('客服消息内容为空');
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
try {
|
|
558
|
+
// 获取或创建用户会话
|
|
559
|
+
let sessionInfo = serviceSessions.get(userId);
|
|
560
|
+
let sessionId;
|
|
561
|
+
|
|
562
|
+
if (!sessionInfo) {
|
|
563
|
+
// 如果没有会话,创建一个
|
|
564
|
+
this.logInfo(`[RongyunMessageHandler] 用户 ${userId} 没有现有会话,创建新会话`);
|
|
565
|
+
const session = await createOpencodeSession(`客服会话-${userId}`);
|
|
566
|
+
sessionId = session.id || session.session_id;
|
|
567
|
+
serviceSessions.set(userId, {
|
|
568
|
+
sessionId: sessionId,
|
|
569
|
+
userId: userId,
|
|
570
|
+
createdAt: Date.now(),
|
|
571
|
+
});
|
|
572
|
+
} else {
|
|
573
|
+
sessionId = sessionInfo.sessionId;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
this.logInfo(`[RongyunMessageHandler] 使用会话: ${sessionId}`);
|
|
577
|
+
|
|
578
|
+
// 调用 OpenCode 服务获取回复
|
|
579
|
+
let fullResponse = '';
|
|
580
|
+
await forwardChatMessage(
|
|
581
|
+
sessionId,
|
|
582
|
+
content,
|
|
583
|
+
(delta) => {
|
|
584
|
+
fullResponse += delta;
|
|
585
|
+
},
|
|
586
|
+
(level, message) => {
|
|
587
|
+
if (level === 'ERROR') {
|
|
588
|
+
this.logError(`[SERVICE-CHAT] ${message}`);
|
|
589
|
+
} else {
|
|
590
|
+
this.logInfo(`[SERVICE-CHAT] ${message}`);
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
120000 // 2分钟超时
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
this.logInfo(`[RongyunMessageHandler] 客服回复生成完成, 长度: ${fullResponse.length}`);
|
|
597
|
+
|
|
598
|
+
// 发送客服回复给用户
|
|
599
|
+
await this.sendResponse(
|
|
600
|
+
RongyunMessageTypeEnum.SERVICE_CHAT_RESPONSE,
|
|
601
|
+
{
|
|
602
|
+
status: 'success',
|
|
603
|
+
content: fullResponse,
|
|
604
|
+
sessionId: sessionId,
|
|
605
|
+
userId: userId,
|
|
606
|
+
},
|
|
607
|
+
requestId,
|
|
608
|
+
sourceId
|
|
609
|
+
);
|
|
610
|
+
} catch (e) {
|
|
611
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
612
|
+
this.logError(`客服消息处理异常: ${msg}`);
|
|
613
|
+
|
|
614
|
+
// 发送错误回复
|
|
615
|
+
await this.sendResponse(
|
|
616
|
+
RongyunMessageTypeEnum.SERVICE_CHAT_RESPONSE,
|
|
617
|
+
{
|
|
618
|
+
status: 'error',
|
|
619
|
+
content: '抱歉,处理您的消息时出现问题,请稍后重试。',
|
|
620
|
+
userId: userId,
|
|
621
|
+
},
|
|
622
|
+
requestId,
|
|
623
|
+
sourceId
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
464
628
|
async sendResponse(msgType, content, requestId, targetId) {
|
|
465
629
|
if (!this.messageSender) {
|
|
466
630
|
this.logError('MessageSender 未设置,无法发送响应');
|
|
@@ -176,7 +176,15 @@ class RongyunMessageSender {
|
|
|
176
176
|
|
|
177
177
|
// 优先使用自定义消息类型发送 P2P 消息
|
|
178
178
|
let result;
|
|
179
|
-
if (this.rongcloudClient.
|
|
179
|
+
if (this.rongcloudClient.ServiceChatMessage && msgType.includes('service')) {
|
|
180
|
+
// 客服相关消息使用 service_chat 自定义消息类型
|
|
181
|
+
result = await this.rongcloudClient.sendCustomMessage(
|
|
182
|
+
targetId,
|
|
183
|
+
messagePayload,
|
|
184
|
+
1, // PRIVATE
|
|
185
|
+
'service_chat'
|
|
186
|
+
);
|
|
187
|
+
} else if (this.rongcloudClient.SystemServiceMessage) {
|
|
180
188
|
result = await this.rongcloudClient.sendCustomMessage(
|
|
181
189
|
targetId,
|
|
182
190
|
messagePayload,
|
|
@@ -26,7 +26,11 @@ const RongyunMessageTypeEnum = {
|
|
|
26
26
|
DEVICE_CONTROL: "device_control",
|
|
27
27
|
DEVICE_CONTROL_RESULT: "device_control_result",
|
|
28
28
|
DEVICE_STATUS_REQUEST: "device_status_request",
|
|
29
|
-
DEVICE_STATUS_REPORT: "device_status_report"
|
|
29
|
+
DEVICE_STATUS_REPORT: "device_status_report",
|
|
30
|
+
SERVICE_CHAT_MESSAGE: "service_chat_message",
|
|
31
|
+
SERVICE_CHAT_RESPONSE: "service_chat_response",
|
|
32
|
+
CREATE_SERVICE_SESSION: "create_service_session",
|
|
33
|
+
SERVICE_SESSION_CREATED: "service_session_created"
|
|
30
34
|
};
|
|
31
35
|
|
|
32
36
|
module.exports = { RongyunMessageTypeEnum };
|
|
@@ -44,11 +44,15 @@ class RongCloudClient {
|
|
|
44
44
|
if (typeof RongIMLib.registerMessageType === 'function') {
|
|
45
45
|
this.SystemServiceMessage = RongIMLib.registerMessageType('command', false, false);
|
|
46
46
|
this.log?.info('[RongCloudClient] command 自定义消息类型已注册');
|
|
47
|
+
|
|
48
|
+
// 注册 service_chat 自定义消息类型(客服消息)
|
|
49
|
+
this.ServiceChatMessage = RongIMLib.registerMessageType('service_chat', false, false);
|
|
50
|
+
this.log?.info('[RongCloudClient] service_chat 自定义消息类型已注册');
|
|
47
51
|
} else {
|
|
48
52
|
this.log?.warn('[RongCloudClient] SDK 不支持 registerMessageType');
|
|
49
53
|
}
|
|
50
54
|
} catch (err) {
|
|
51
|
-
this.log?.warn(`[RongCloudClient]
|
|
55
|
+
this.log?.warn(`[RongCloudClient] 注册自定义消息类型失败: ${err.message}`);
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
this.log?.info(`[RongCloudClient] SDK Events: ${JSON.stringify(Object.keys(RongIMLib.Events || {}))}`);
|
|
@@ -286,8 +290,14 @@ class RongCloudClient {
|
|
|
286
290
|
return false;
|
|
287
291
|
}
|
|
288
292
|
|
|
289
|
-
|
|
290
|
-
|
|
293
|
+
// 根据消息类型选择对应的构造函数
|
|
294
|
+
let MessageCtor = this.SystemServiceMessage;
|
|
295
|
+
if (customType === 'service_chat') {
|
|
296
|
+
MessageCtor = this.ServiceChatMessage;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (!MessageCtor) {
|
|
300
|
+
this.log?.error(`[RongCloudClient] ${customType} 消息类型未注册`);
|
|
291
301
|
return false;
|
|
292
302
|
}
|
|
293
303
|
|
|
@@ -297,7 +307,7 @@ class RongCloudClient {
|
|
|
297
307
|
: (RongIMLib.ConversationType?.PRIVATE || ConversationType.PRIVATE);
|
|
298
308
|
|
|
299
309
|
const messageContent = typeof content === 'string' ? JSON.parse(content) : content;
|
|
300
|
-
const customMsg = new
|
|
310
|
+
const customMsg = new MessageCtor(messageContent);
|
|
301
311
|
|
|
302
312
|
const result = await RongIMLib.sendMessage(
|
|
303
313
|
{ conversationType: convType, targetId },
|