acp-ts 1.1.8 → 1.2.0
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/agentcp.d.ts +15 -17
- package/dist/agentcp.js +48 -56
- package/dist/group/client.js +23 -21
- package/dist/group/events.d.ts +2 -2
- package/dist/group/events.js +0 -3
- package/dist/group/index.d.ts +1 -1
- package/dist/group/index.js +3 -2
- package/dist/group/operations.d.ts +6 -7
- package/dist/group/operations.js +8 -20
- package/dist/group/types.d.ts +7 -4
- package/dist/group/types.js +5 -2
- package/dist/server.js +28 -16
- package/package.json +1 -1
package/dist/agentcp.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IAgentCP, IAgentIdentity } from "./interfaces";
|
|
2
2
|
import { MessageStore } from "./messagestore";
|
|
3
3
|
import { AgentMdOptions } from "./agentmd";
|
|
4
|
-
import { ACPGroupClient, GroupOperations, ACPGroupEventHandler, CursorStore, GroupMessageStore, GroupMessage,
|
|
4
|
+
import { ACPGroupClient, GroupOperations, ACPGroupEventHandler, CursorStore, GroupMessageStore, GroupMessage, GroupMessageBatch } from "./group";
|
|
5
5
|
declare class AgentCP implements IAgentCP {
|
|
6
6
|
private seedPassword;
|
|
7
7
|
private apUrl;
|
|
@@ -90,15 +90,20 @@ declare class AgentCP implements IAgentCP {
|
|
|
90
90
|
setGroupEventHandler(handler: ACPGroupEventHandler): void;
|
|
91
91
|
/**
|
|
92
92
|
* 创建默认的群组事件处理器。
|
|
93
|
-
* -
|
|
93
|
+
* - onGroupMessageBatch: 自动存储消息 + watermark ACK
|
|
94
94
|
* - onJoinApproved: 自动注册到 Home AP + 存储群组
|
|
95
95
|
* 外部可通过 setGroupEventHandler 覆盖。
|
|
96
96
|
*/
|
|
97
97
|
private _createDefaultGroupEventHandler;
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
99
|
+
* 处理批量推送消息:排序、存储、ACK 最后一条。
|
|
100
|
+
* 返回排序后的消息列表,供上层使用(如推送给浏览器)。
|
|
100
101
|
*/
|
|
101
|
-
|
|
102
|
+
processAndAckBatch(groupId: string, batch: GroupMessageBatch): GroupMessage[];
|
|
103
|
+
/**
|
|
104
|
+
* 异步 ACK 消息(不阻塞调用方)
|
|
105
|
+
*/
|
|
106
|
+
private _ackMessage;
|
|
102
107
|
/**
|
|
103
108
|
* 设置群组游标存储
|
|
104
109
|
*/
|
|
@@ -142,10 +147,6 @@ declare class AgentCP implements IAgentCP {
|
|
|
142
147
|
* 添加群组到本地存储
|
|
143
148
|
*/
|
|
144
149
|
addGroupToStore(groupId: string, name: string): void;
|
|
145
|
-
/**
|
|
146
|
-
* 将加入的群组注册到 Home AP(内部方法)
|
|
147
|
-
*/
|
|
148
|
-
registerGroupToHomeAP(groupId: string, groupUrl: string, role?: string): Promise<void>;
|
|
149
150
|
/**
|
|
150
151
|
* 从本地存储删除群组
|
|
151
152
|
*/
|
|
@@ -178,18 +179,15 @@ declare class AgentCP implements IAgentCP {
|
|
|
178
179
|
pullAndStoreGroupMessages(groupId: string, afterMsgId?: number, limit?: number): Promise<GroupMessage[]>;
|
|
179
180
|
/**
|
|
180
181
|
* 加入群组会话(完整生命周期):
|
|
181
|
-
* 1. register_online →
|
|
182
|
-
* 2.
|
|
182
|
+
* 1. register_online → 告知 group.ap 在线
|
|
183
|
+
* 2. 将群组加入在线列表
|
|
183
184
|
* 3. 启动心跳定时器(首次时启动)
|
|
184
|
-
*
|
|
185
|
-
* @returns msg_cursor 游标状态
|
|
186
185
|
*/
|
|
187
|
-
joinGroupSession(groupId: string): Promise<
|
|
186
|
+
joinGroupSession(groupId: string): Promise<void>;
|
|
188
187
|
/**
|
|
189
188
|
* 离开群组会话(优雅退出):
|
|
190
|
-
* 1.
|
|
191
|
-
* 2.
|
|
192
|
-
* 3. 如果没有在线群组了,停止心跳定时器
|
|
189
|
+
* 1. 从在线群组列表移除
|
|
190
|
+
* 2. 如果没有在线群组了,unregister_online + 停止心跳定时器
|
|
193
191
|
*/
|
|
194
192
|
leaveGroupSession(groupId: string): Promise<void>;
|
|
195
193
|
/**
|
|
@@ -213,7 +211,7 @@ declare class AgentCP implements IAgentCP {
|
|
|
213
211
|
*/
|
|
214
212
|
private _stopHeartbeat;
|
|
215
213
|
/**
|
|
216
|
-
*
|
|
214
|
+
* 发送心跳保活
|
|
217
215
|
*/
|
|
218
216
|
private _sendHeartbeats;
|
|
219
217
|
/**
|
package/dist/agentcp.js
CHANGED
|
@@ -61,7 +61,7 @@ class AgentCP {
|
|
|
61
61
|
this.groupMessageStore = null;
|
|
62
62
|
this._groupTargetAid = '';
|
|
63
63
|
this._groupSessionId = '';
|
|
64
|
-
this._persistGroupMessages =
|
|
64
|
+
this._persistGroupMessages = true;
|
|
65
65
|
// Group lifecycle management
|
|
66
66
|
this._onlineGroups = new Set();
|
|
67
67
|
this._heartbeatTimer = null;
|
|
@@ -80,7 +80,7 @@ class AgentCP {
|
|
|
80
80
|
this._basePath = basePath || process.cwd();
|
|
81
81
|
this.apUrl = `${baseUrl}/api/accesspoint`;
|
|
82
82
|
this.msgUrl = `${baseUrl}/api/message`;
|
|
83
|
-
this._persistGroupMessages = (_a = options === null || options === void 0 ? void 0 : options.persistGroupMessages) !== null && _a !== void 0 ? _a :
|
|
83
|
+
this._persistGroupMessages = (_a = options === null || options === void 0 ? void 0 : options.persistGroupMessages) !== null && _a !== void 0 ? _a : true;
|
|
84
84
|
this._messageStore = new messagestore_1.MessageStore({
|
|
85
85
|
persistMessages: (_b = options === null || options === void 0 ? void 0 : options.persistMessages) !== null && _b !== void 0 ? _b : false,
|
|
86
86
|
basePath: this._basePath,
|
|
@@ -401,7 +401,7 @@ class AgentCP {
|
|
|
401
401
|
}
|
|
402
402
|
/**
|
|
403
403
|
* 创建默认的群组事件处理器。
|
|
404
|
-
* -
|
|
404
|
+
* - onGroupMessageBatch: 自动存储消息 + watermark ACK
|
|
405
405
|
* - onJoinApproved: 自动注册到 Home AP + 存储群组
|
|
406
406
|
* 外部可通过 setGroupEventHandler 覆盖。
|
|
407
407
|
*/
|
|
@@ -431,8 +431,6 @@ class AgentCP {
|
|
|
431
431
|
}
|
|
432
432
|
catch (_) { }
|
|
433
433
|
this.addGroupToStore(groupId, groupName);
|
|
434
|
-
const groupUrl = groupAddress || `https://${this._groupTargetAid}/${groupId}`;
|
|
435
|
-
await this.registerGroupToHomeAP(groupId, groupUrl);
|
|
436
434
|
}
|
|
437
435
|
catch (e) {
|
|
438
436
|
console.error(`[Group][DefaultHandler] onJoinApproved processing failed: group=${groupId}`, e.message);
|
|
@@ -445,12 +443,9 @@ class AgentCP {
|
|
|
445
443
|
onJoinRequestReceived(groupId, agentId, message) {
|
|
446
444
|
console.log(`[Group][DefaultHandler] onJoinRequestReceived: group=${groupId} agent=${agentId}`);
|
|
447
445
|
},
|
|
448
|
-
|
|
449
|
-
console.log(`[Group][DefaultHandler]
|
|
450
|
-
|
|
451
|
-
this.addGroupMessageToStore(groupId, msg);
|
|
452
|
-
// 自动 ACK(异步,不阻塞回调)
|
|
453
|
-
this._autoAckMessage(groupId, msg.msg_id);
|
|
446
|
+
onGroupMessageBatch: (groupId, batch) => {
|
|
447
|
+
console.log(`[Group][DefaultHandler] onGroupMessageBatch: group=${groupId} count=${batch.count} range=[${batch.start_msg_id}, ${batch.latest_msg_id}]`);
|
|
448
|
+
this.processAndAckBatch(groupId, batch);
|
|
454
449
|
},
|
|
455
450
|
onGroupEvent(groupId, evt) {
|
|
456
451
|
console.log(`[Group][DefaultHandler] onGroupEvent: group=${groupId} event=${evt.event_type}`);
|
|
@@ -458,13 +453,27 @@ class AgentCP {
|
|
|
458
453
|
};
|
|
459
454
|
}
|
|
460
455
|
/**
|
|
461
|
-
*
|
|
456
|
+
* 处理批量推送消息:排序、存储、ACK 最后一条。
|
|
457
|
+
* 返回排序后的消息列表,供上层使用(如推送给浏览器)。
|
|
462
458
|
*/
|
|
463
|
-
|
|
459
|
+
processAndAckBatch(groupId, batch) {
|
|
460
|
+
const sorted = [...batch.messages].sort((a, b) => a.msg_id - b.msg_id);
|
|
461
|
+
this.addGroupMessagesToStore(groupId, sorted);
|
|
462
|
+
// ACK batch 中最后一条消息
|
|
463
|
+
if (sorted.length > 0) {
|
|
464
|
+
const lastMsgId = sorted[sorted.length - 1].msg_id;
|
|
465
|
+
this._ackMessage(groupId, lastMsgId);
|
|
466
|
+
}
|
|
467
|
+
return sorted;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* 异步 ACK 消息(不阻塞调用方)
|
|
471
|
+
*/
|
|
472
|
+
_ackMessage(groupId, msgId) {
|
|
464
473
|
if (!this.groupOps || !this._groupTargetAid)
|
|
465
474
|
return;
|
|
466
475
|
this.groupOps.ackMessages(this._groupTargetAid, groupId, msgId).catch(e => {
|
|
467
|
-
console.warn(`[Group]
|
|
476
|
+
console.warn(`[Group] ack failed: group=${groupId} msgId=${msgId}`, e.message || e);
|
|
468
477
|
});
|
|
469
478
|
}
|
|
470
479
|
/**
|
|
@@ -574,20 +583,6 @@ class AgentCP {
|
|
|
574
583
|
return;
|
|
575
584
|
this.groupMessageStore.getOrCreateGroup(groupId, this._groupTargetAid, name);
|
|
576
585
|
}
|
|
577
|
-
/**
|
|
578
|
-
* 将加入的群组注册到 Home AP(内部方法)
|
|
579
|
-
*/
|
|
580
|
-
async registerGroupToHomeAP(groupId, groupUrl, role = 'member') {
|
|
581
|
-
if (!this.groupOps || !this._groupTargetAid)
|
|
582
|
-
return;
|
|
583
|
-
try {
|
|
584
|
-
await this.groupOps.registerMembership(this._groupTargetAid, groupId, groupUrl, this._groupTargetAid, this._groupSessionId, role);
|
|
585
|
-
console.log(`[Group] registerGroupToHomeAP success: group=${groupId}`);
|
|
586
|
-
}
|
|
587
|
-
catch (e) {
|
|
588
|
-
console.error(`[Group] registerGroupToHomeAP failed: group=${groupId}`, e.message);
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
586
|
/**
|
|
592
587
|
* 从本地存储删除群组
|
|
593
588
|
*/
|
|
@@ -685,47 +680,46 @@ class AgentCP {
|
|
|
685
680
|
// ============================================================
|
|
686
681
|
/**
|
|
687
682
|
* 加入群组会话(完整生命周期):
|
|
688
|
-
* 1. register_online →
|
|
689
|
-
* 2.
|
|
683
|
+
* 1. register_online → 告知 group.ap 在线
|
|
684
|
+
* 2. 将群组加入在线列表
|
|
690
685
|
* 3. 启动心跳定时器(首次时启动)
|
|
691
|
-
*
|
|
692
|
-
* @returns msg_cursor 游标状态
|
|
693
686
|
*/
|
|
694
687
|
async joinGroupSession(groupId) {
|
|
695
688
|
if (!this.groupOps || !this._groupTargetAid) {
|
|
696
689
|
throw new Error('群组客户端未初始化,请先调用 initGroupClient');
|
|
697
690
|
}
|
|
698
|
-
// Step 1: register_online
|
|
699
|
-
|
|
700
|
-
const cursor = result.msg_cursor;
|
|
691
|
+
// Step 1: register_online(仅通知 group.ap 在线,不再返回游标)
|
|
692
|
+
await this.groupOps.registerOnline(this._groupTargetAid);
|
|
701
693
|
this._onlineGroups.add(groupId);
|
|
702
|
-
console.log(`[Group] joinGroupSession: group=${groupId}
|
|
703
|
-
// Step 2:
|
|
704
|
-
|
|
705
|
-
|
|
694
|
+
console.log(`[Group] joinGroupSession: group=${groupId}`);
|
|
695
|
+
// Step 2: 冷启动同步 — 拉取历史消息对齐,再进入批推送接收
|
|
696
|
+
try {
|
|
697
|
+
const lastMsgId = this.getGroupLastMsgId(groupId);
|
|
698
|
+
await this.pullAndStoreGroupMessages(groupId, lastMsgId, 50);
|
|
699
|
+
}
|
|
700
|
+
catch (e) {
|
|
701
|
+
console.warn(`[Group] cold-start sync failed: group=${groupId}`, e.message || e);
|
|
706
702
|
}
|
|
707
703
|
// Step 3: 启动心跳定时器(首次加入群组时启动)
|
|
708
704
|
this._ensureHeartbeat();
|
|
709
|
-
return cursor;
|
|
710
705
|
}
|
|
711
706
|
/**
|
|
712
707
|
* 离开群组会话(优雅退出):
|
|
713
|
-
* 1.
|
|
714
|
-
* 2.
|
|
715
|
-
* 3. 如果没有在线群组了,停止心跳定时器
|
|
708
|
+
* 1. 从在线群组列表移除
|
|
709
|
+
* 2. 如果没有在线群组了,unregister_online + 停止心跳定时器
|
|
716
710
|
*/
|
|
717
711
|
async leaveGroupSession(groupId) {
|
|
718
712
|
if (!this.groupOps || !this._groupTargetAid)
|
|
719
713
|
return;
|
|
720
|
-
try {
|
|
721
|
-
await this.groupOps.unregisterOnline(this._groupTargetAid, groupId);
|
|
722
|
-
}
|
|
723
|
-
catch (e) {
|
|
724
|
-
console.warn(`[Group] unregisterOnline failed: group=${groupId}`, e.message || e);
|
|
725
|
-
}
|
|
726
714
|
this._onlineGroups.delete(groupId);
|
|
727
|
-
//
|
|
715
|
+
// 如果没有在线群组了,通知 group.ap 下线并停止心跳
|
|
728
716
|
if (this._onlineGroups.size === 0) {
|
|
717
|
+
try {
|
|
718
|
+
await this.groupOps.unregisterOnline(this._groupTargetAid);
|
|
719
|
+
}
|
|
720
|
+
catch (e) {
|
|
721
|
+
console.warn(`[Group] unregisterOnline failed`, e.message || e);
|
|
722
|
+
}
|
|
729
723
|
this._stopHeartbeat();
|
|
730
724
|
}
|
|
731
725
|
}
|
|
@@ -779,16 +773,14 @@ class AgentCP {
|
|
|
779
773
|
}
|
|
780
774
|
}
|
|
781
775
|
/**
|
|
782
|
-
*
|
|
776
|
+
* 发送心跳保活
|
|
783
777
|
*/
|
|
784
778
|
_sendHeartbeats() {
|
|
785
779
|
if (!this.groupOps || !this._groupTargetAid)
|
|
786
780
|
return;
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
});
|
|
791
|
-
}
|
|
781
|
+
this.groupOps.heartbeat(this._groupTargetAid).catch(e => {
|
|
782
|
+
console.warn(`[Group] heartbeat failed`, e.message || e);
|
|
783
|
+
});
|
|
792
784
|
}
|
|
793
785
|
/**
|
|
794
786
|
* 关闭群消息存储,刷新所有未写入的数据
|
package/dist/group/client.js
CHANGED
|
@@ -74,7 +74,7 @@ class ACPGroupClient {
|
|
|
74
74
|
* Called by the message dispatch chain in AgentCP.
|
|
75
75
|
*/
|
|
76
76
|
handleIncoming(payload) {
|
|
77
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j
|
|
77
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
78
78
|
let data;
|
|
79
79
|
try {
|
|
80
80
|
data = JSON.parse(payload);
|
|
@@ -116,31 +116,33 @@ class ACPGroupClient {
|
|
|
116
116
|
}
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
|
-
// Handle
|
|
120
|
-
// These have action field but no event/request_id, need to be mapped to notification events
|
|
119
|
+
// Handle batch push from group.ap
|
|
121
120
|
const action = (_d = data.action) !== null && _d !== void 0 ? _d : "";
|
|
122
|
-
if (action ===
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
121
|
+
if (action === types_1.ACTION_MESSAGE_BATCH_PUSH && data.data) {
|
|
122
|
+
const batchData = data.data;
|
|
123
|
+
const batch = {
|
|
124
|
+
messages: ((_e = batchData.messages) !== null && _e !== void 0 ? _e : []).map((m) => {
|
|
125
|
+
var _a, _b, _c, _d, _e, _f;
|
|
126
|
+
return ({
|
|
127
|
+
msg_id: (_a = m.msg_id) !== null && _a !== void 0 ? _a : 0,
|
|
128
|
+
sender: (_b = m.sender) !== null && _b !== void 0 ? _b : "",
|
|
129
|
+
content: (_c = m.content) !== null && _c !== void 0 ? _c : "",
|
|
130
|
+
content_type: (_d = m.content_type) !== null && _d !== void 0 ? _d : "text/plain",
|
|
131
|
+
timestamp: (_e = m.timestamp) !== null && _e !== void 0 ? _e : 0,
|
|
132
|
+
metadata: (_f = m.metadata) !== null && _f !== void 0 ? _f : null,
|
|
133
|
+
});
|
|
134
|
+
}),
|
|
135
|
+
start_msg_id: (_f = batchData.start_msg_id) !== null && _f !== void 0 ? _f : 0,
|
|
136
|
+
latest_msg_id: (_g = batchData.latest_msg_id) !== null && _g !== void 0 ? _g : 0,
|
|
137
|
+
count: (_h = batchData.count) !== null && _h !== void 0 ? _h : 0,
|
|
138
138
|
};
|
|
139
|
+
const groupId = (_j = data.group_id) !== null && _j !== void 0 ? _j : "";
|
|
140
|
+
console.log(`[GroupClient] message_batch_push: group=${groupId} count=${batch.count} range=[${batch.start_msg_id}, ${batch.latest_msg_id}]`);
|
|
139
141
|
if (this._handler != null) {
|
|
140
|
-
|
|
142
|
+
this._handler.onGroupMessageBatch(groupId, batch);
|
|
141
143
|
}
|
|
142
144
|
else {
|
|
143
|
-
console.warn(`[GroupClient] !!!
|
|
145
|
+
console.warn(`[GroupClient] !!! message_batch_push dropped: no event handler registered.`);
|
|
144
146
|
}
|
|
145
147
|
return;
|
|
146
148
|
}
|
package/dist/group/events.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Group event handler interfaces and dispatch logic.
|
|
3
3
|
* Mirrors Python SDK: agentcp/group/events.py
|
|
4
4
|
*/
|
|
5
|
-
import { GroupNotify,
|
|
5
|
+
import { GroupNotify, GroupEvent, GroupMessageBatch } from './types';
|
|
6
6
|
/**
|
|
7
7
|
* Abstract handler for ACP group notifications.
|
|
8
8
|
*/
|
|
@@ -13,7 +13,7 @@ export interface ACPGroupEventHandler {
|
|
|
13
13
|
onJoinApproved(groupId: string, groupAddress: string): void;
|
|
14
14
|
onJoinRejected(groupId: string, reason: string): void;
|
|
15
15
|
onJoinRequestReceived(groupId: string, agentId: string, message: string): void;
|
|
16
|
-
|
|
16
|
+
onGroupMessageBatch(groupId: string, batch: GroupMessageBatch): void;
|
|
17
17
|
onGroupEvent(groupId: string, evt: GroupEvent): void;
|
|
18
18
|
}
|
|
19
19
|
/**
|
package/dist/group/events.js
CHANGED
|
@@ -38,9 +38,6 @@ function dispatchAcpNotify(handler, notify) {
|
|
|
38
38
|
else if (event === types_1.NOTIFY_JOIN_REQUEST_RECEIVED) {
|
|
39
39
|
handler.onJoinRequestReceived(gid, (_l = data.agent_id) !== null && _l !== void 0 ? _l : "", (_m = data.message) !== null && _m !== void 0 ? _m : "");
|
|
40
40
|
}
|
|
41
|
-
else if (event === types_1.NOTIFY_GROUP_MESSAGE) {
|
|
42
|
-
handler.onGroupMessage(gid, data);
|
|
43
|
-
}
|
|
44
41
|
else if (event === types_1.NOTIFY_GROUP_EVENT) {
|
|
45
42
|
handler.onGroupEvent(gid, data);
|
|
46
43
|
}
|
package/dist/group/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ACP Group Operations package.
|
|
3
3
|
* Mirrors Python SDK: agentcp/group/__init__.py
|
|
4
4
|
*/
|
|
5
|
-
export { GroupErrorCode, GroupError, GroupRequest, GroupResponse, GroupNotify, buildGroupRequest, groupRequestToJson, parseGroupResponse, parseGroupNotify, GroupMessage, GroupEvent, MsgCursor, EventCursor, CursorState, createMsgCursor, createEventCursor,
|
|
5
|
+
export { GroupErrorCode, GroupError, GroupRequest, GroupResponse, GroupNotify, buildGroupRequest, groupRequestToJson, parseGroupResponse, parseGroupNotify, GroupMessage, GroupEvent, MsgCursor, EventCursor, CursorState, createMsgCursor, createEventCursor, CreateGroupResp, SendMessageResp, PullMessagesResp, PullEventsResp, GroupInfoResp, BanlistResp, BatchReviewResp, PendingRequestsResp, MembersResp, AdminsResp, RulesResp, AnnouncementResp, JoinRequirementsResp, MasterResp, InviteCodeResp, InviteCodeListResp, BroadcastLockResp, BroadcastPermissionResp, SyncStatusResp, SyncLogResp, ChecksumResp, PublicGroupInfoResp, SearchGroupsResp, DigestResp, MembershipInfo, ListMyGroupsResp, GetFileResp, GetSummaryResp, GetMetricsResp, NOTIFY_NEW_MESSAGE, NOTIFY_NEW_EVENT, NOTIFY_GROUP_INVITE, NOTIFY_JOIN_APPROVED, NOTIFY_JOIN_REJECTED, NOTIFY_JOIN_REQUEST_RECEIVED, NOTIFY_GROUP_EVENT, EVENT_MEMBER_JOINED, EVENT_MEMBER_REMOVED, EVENT_MEMBER_LEFT, EVENT_MEMBER_BANNED, EVENT_META_UPDATED, EVENT_RULES_UPDATED, EVENT_ANNOUNCEMENT_UPDATED, EVENT_GROUP_DISSOLVED, EVENT_MASTER_TRANSFERRED, EVENT_GROUP_SUSPENDED, EVENT_GROUP_RESUMED, EVENT_MEMBER_UNBANNED, EVENT_JOIN_REQUIREMENTS_UPDATED, EVENT_INVITE_CODE_CREATED, EVENT_INVITE_CODE_REVOKED, ACTION_MESSAGE_BATCH_PUSH, GroupMessageBatch, } from './types';
|
|
6
6
|
export { ACPGroupClient, SendFunc } from './client';
|
|
7
7
|
export { GroupOperations, SyncHandler } from './operations';
|
|
8
8
|
export { ACPGroupEventHandler, EventProcessor, dispatchAcpNotify, dispatchEvent, } from './events';
|
package/dist/group/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Mirrors Python SDK: agentcp/group/__init__.py
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.GroupMessageStore = exports.LocalCursorStore = exports.dispatchAcpNotify = exports.GroupOperations = exports.ACPGroupClient = exports.EVENT_INVITE_CODE_REVOKED = exports.EVENT_INVITE_CODE_CREATED = exports.EVENT_JOIN_REQUIREMENTS_UPDATED = exports.EVENT_MEMBER_UNBANNED = exports.EVENT_GROUP_RESUMED = exports.EVENT_GROUP_SUSPENDED = exports.EVENT_MASTER_TRANSFERRED = exports.EVENT_GROUP_DISSOLVED = exports.EVENT_ANNOUNCEMENT_UPDATED = exports.EVENT_RULES_UPDATED = exports.EVENT_META_UPDATED = exports.EVENT_MEMBER_BANNED = exports.EVENT_MEMBER_LEFT = exports.EVENT_MEMBER_REMOVED = exports.EVENT_MEMBER_JOINED = exports.NOTIFY_GROUP_EVENT = exports.
|
|
7
|
+
exports.GroupMessageStore = exports.LocalCursorStore = exports.dispatchAcpNotify = exports.GroupOperations = exports.ACPGroupClient = exports.ACTION_MESSAGE_BATCH_PUSH = exports.EVENT_INVITE_CODE_REVOKED = exports.EVENT_INVITE_CODE_CREATED = exports.EVENT_JOIN_REQUIREMENTS_UPDATED = exports.EVENT_MEMBER_UNBANNED = exports.EVENT_GROUP_RESUMED = exports.EVENT_GROUP_SUSPENDED = exports.EVENT_MASTER_TRANSFERRED = exports.EVENT_GROUP_DISSOLVED = exports.EVENT_ANNOUNCEMENT_UPDATED = exports.EVENT_RULES_UPDATED = exports.EVENT_META_UPDATED = exports.EVENT_MEMBER_BANNED = exports.EVENT_MEMBER_LEFT = exports.EVENT_MEMBER_REMOVED = exports.EVENT_MEMBER_JOINED = exports.NOTIFY_GROUP_EVENT = exports.NOTIFY_JOIN_REQUEST_RECEIVED = exports.NOTIFY_JOIN_REJECTED = exports.NOTIFY_JOIN_APPROVED = exports.NOTIFY_GROUP_INVITE = exports.NOTIFY_NEW_EVENT = exports.NOTIFY_NEW_MESSAGE = exports.createEventCursor = exports.createMsgCursor = exports.parseGroupNotify = exports.parseGroupResponse = exports.groupRequestToJson = exports.buildGroupRequest = exports.GroupError = exports.GroupErrorCode = void 0;
|
|
8
8
|
// Types
|
|
9
9
|
var types_1 = require("./types");
|
|
10
10
|
Object.defineProperty(exports, "GroupErrorCode", { enumerable: true, get: function () { return types_1.GroupErrorCode; } });
|
|
@@ -22,7 +22,6 @@ Object.defineProperty(exports, "NOTIFY_GROUP_INVITE", { enumerable: true, get: f
|
|
|
22
22
|
Object.defineProperty(exports, "NOTIFY_JOIN_APPROVED", { enumerable: true, get: function () { return types_1.NOTIFY_JOIN_APPROVED; } });
|
|
23
23
|
Object.defineProperty(exports, "NOTIFY_JOIN_REJECTED", { enumerable: true, get: function () { return types_1.NOTIFY_JOIN_REJECTED; } });
|
|
24
24
|
Object.defineProperty(exports, "NOTIFY_JOIN_REQUEST_RECEIVED", { enumerable: true, get: function () { return types_1.NOTIFY_JOIN_REQUEST_RECEIVED; } });
|
|
25
|
-
Object.defineProperty(exports, "NOTIFY_GROUP_MESSAGE", { enumerable: true, get: function () { return types_1.NOTIFY_GROUP_MESSAGE; } });
|
|
26
25
|
Object.defineProperty(exports, "NOTIFY_GROUP_EVENT", { enumerable: true, get: function () { return types_1.NOTIFY_GROUP_EVENT; } });
|
|
27
26
|
// Group event type constants
|
|
28
27
|
Object.defineProperty(exports, "EVENT_MEMBER_JOINED", { enumerable: true, get: function () { return types_1.EVENT_MEMBER_JOINED; } });
|
|
@@ -40,6 +39,8 @@ Object.defineProperty(exports, "EVENT_MEMBER_UNBANNED", { enumerable: true, get:
|
|
|
40
39
|
Object.defineProperty(exports, "EVENT_JOIN_REQUIREMENTS_UPDATED", { enumerable: true, get: function () { return types_1.EVENT_JOIN_REQUIREMENTS_UPDATED; } });
|
|
41
40
|
Object.defineProperty(exports, "EVENT_INVITE_CODE_CREATED", { enumerable: true, get: function () { return types_1.EVENT_INVITE_CODE_CREATED; } });
|
|
42
41
|
Object.defineProperty(exports, "EVENT_INVITE_CODE_REVOKED", { enumerable: true, get: function () { return types_1.EVENT_INVITE_CODE_REVOKED; } });
|
|
42
|
+
// Batch push
|
|
43
|
+
Object.defineProperty(exports, "ACTION_MESSAGE_BATCH_PUSH", { enumerable: true, get: function () { return types_1.ACTION_MESSAGE_BATCH_PUSH; } });
|
|
43
44
|
// Client
|
|
44
45
|
var client_1 = require("./client");
|
|
45
46
|
Object.defineProperty(exports, "ACPGroupClient", { enumerable: true, get: function () { return client_1.ACPGroupClient; } });
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Mirrors Python SDK: agentcp/group/operations.py
|
|
4
4
|
*/
|
|
5
5
|
import { ACPGroupClient } from './client';
|
|
6
|
-
import {
|
|
6
|
+
import { CreateGroupResp, SendMessageResp, PullMessagesResp, PullEventsResp, CursorState, GroupInfoResp, BanlistResp, BatchReviewResp, PendingRequestsResp, MembersResp, AdminsResp, RulesResp, AnnouncementResp, JoinRequirementsResp, MasterResp, InviteCodeResp, InviteCodeListResp, BroadcastLockResp, BroadcastPermissionResp, SyncStatusResp, SyncLogResp, ChecksumResp, PublicGroupInfoResp, SearchGroupsResp, DigestResp, ListMyGroupsResp, GetFileResp, GetSummaryResp, GetMetricsResp } from './types';
|
|
7
7
|
/**
|
|
8
8
|
* Callback interface for syncGroup.
|
|
9
9
|
*/
|
|
@@ -43,20 +43,20 @@ export declare class GroupOperations {
|
|
|
43
43
|
message?: string;
|
|
44
44
|
}): Promise<string>;
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
46
|
+
* 注册上线,告知 group.ap 当前客户端在线,可以接收消息推送。
|
|
47
|
+
* 客户端每次启动或重新连接时调用一次即可。
|
|
48
48
|
*/
|
|
49
|
-
registerOnline(targetAid: string
|
|
49
|
+
registerOnline(targetAid: string): Promise<void>;
|
|
50
50
|
/**
|
|
51
51
|
* 主动下线(优雅退出)。
|
|
52
52
|
* 客户端退出时调用,立即从在线列表移除。
|
|
53
53
|
*/
|
|
54
|
-
unregisterOnline(targetAid: string
|
|
54
|
+
unregisterOnline(targetAid: string): Promise<void>;
|
|
55
55
|
/**
|
|
56
56
|
* 心跳保活。
|
|
57
57
|
* 在线注册有 5 分钟超时,SDK 需定时发送(建议 2~4 分钟)。
|
|
58
58
|
*/
|
|
59
|
-
heartbeat(targetAid: string
|
|
59
|
+
heartbeat(targetAid: string): Promise<void>;
|
|
60
60
|
createGroup(targetAid: string, name: string, options?: {
|
|
61
61
|
alias?: string;
|
|
62
62
|
subject?: string;
|
|
@@ -126,7 +126,6 @@ export declare class GroupOperations {
|
|
|
126
126
|
}): Promise<SearchGroupsResp>;
|
|
127
127
|
generateDigest(targetAid: string, groupId: string, date: string, period: string): Promise<DigestResp>;
|
|
128
128
|
getDigest(targetAid: string, groupId: string, date: string, period: string): Promise<DigestResp>;
|
|
129
|
-
registerMembership(targetAid: string, groupId: string, groupUrl: string, groupServer: string, sessionId: string, role: string): Promise<void>;
|
|
130
129
|
listMyGroups(targetAid: string, status?: number): Promise<ListMyGroupsResp>;
|
|
131
130
|
unregisterMembership(targetAid: string, groupId: string): Promise<void>;
|
|
132
131
|
changeMemberRole(targetAid: string, groupId: string, agentId: string, newRole: string): Promise<void>;
|
package/dist/group/operations.js
CHANGED
|
@@ -62,31 +62,27 @@ class GroupOperations {
|
|
|
62
62
|
// Phase 0: Lifecycle (register / heartbeat / unregister)
|
|
63
63
|
// ============================================================
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
65
|
+
* 注册上线,告知 group.ap 当前客户端在线,可以接收消息推送。
|
|
66
|
+
* 客户端每次启动或重新连接时调用一次即可。
|
|
67
67
|
*/
|
|
68
|
-
async registerOnline(targetAid
|
|
69
|
-
const resp = await this._client.sendRequest(targetAid,
|
|
68
|
+
async registerOnline(targetAid) {
|
|
69
|
+
const resp = await this._client.sendRequest(targetAid, "", "register_online", null);
|
|
70
70
|
this._check(resp, "register_online");
|
|
71
|
-
const d = resp.data || {};
|
|
72
|
-
return {
|
|
73
|
-
msg_cursor: (0, types_1.createMsgCursor)(d.msg_cursor),
|
|
74
|
-
};
|
|
75
71
|
}
|
|
76
72
|
/**
|
|
77
73
|
* 主动下线(优雅退出)。
|
|
78
74
|
* 客户端退出时调用,立即从在线列表移除。
|
|
79
75
|
*/
|
|
80
|
-
async unregisterOnline(targetAid
|
|
81
|
-
const resp = await this._client.sendRequest(targetAid,
|
|
76
|
+
async unregisterOnline(targetAid) {
|
|
77
|
+
const resp = await this._client.sendRequest(targetAid, "", "unregister_online", null);
|
|
82
78
|
this._check(resp, "unregister_online");
|
|
83
79
|
}
|
|
84
80
|
/**
|
|
85
81
|
* 心跳保活。
|
|
86
82
|
* 在线注册有 5 分钟超时,SDK 需定时发送(建议 2~4 分钟)。
|
|
87
83
|
*/
|
|
88
|
-
async heartbeat(targetAid
|
|
89
|
-
const resp = await this._client.sendRequest(targetAid,
|
|
84
|
+
async heartbeat(targetAid) {
|
|
85
|
+
const resp = await this._client.sendRequest(targetAid, "", "heartbeat", null);
|
|
90
86
|
this._check(resp, "heartbeat");
|
|
91
87
|
}
|
|
92
88
|
// ============================================================
|
|
@@ -562,14 +558,6 @@ class GroupOperations {
|
|
|
562
558
|
// ============================================================
|
|
563
559
|
// Phase 5: Home AP Membership Index
|
|
564
560
|
// ============================================================
|
|
565
|
-
async registerMembership(targetAid, groupId, groupUrl, groupServer, sessionId, role) {
|
|
566
|
-
const params = {
|
|
567
|
-
group_id: groupId, group_url: groupUrl,
|
|
568
|
-
group_server: groupServer, session_id: sessionId, role,
|
|
569
|
-
};
|
|
570
|
-
const resp = await this._client.sendRequest(targetAid, groupId, "register_membership", params);
|
|
571
|
-
this._check(resp, "register_membership");
|
|
572
|
-
}
|
|
573
561
|
async listMyGroups(targetAid, status = 0) {
|
|
574
562
|
var _a, _b;
|
|
575
563
|
const params = {};
|
package/dist/group/types.d.ts
CHANGED
|
@@ -85,9 +85,6 @@ export interface CursorState {
|
|
|
85
85
|
msg_cursor: MsgCursor;
|
|
86
86
|
event_cursor: EventCursor;
|
|
87
87
|
}
|
|
88
|
-
export interface RegisterOnlineResp {
|
|
89
|
-
msg_cursor: MsgCursor;
|
|
90
|
-
}
|
|
91
88
|
export interface CreateGroupResp {
|
|
92
89
|
group_id: string;
|
|
93
90
|
group_url: string;
|
|
@@ -250,7 +247,6 @@ export declare const NOTIFY_GROUP_INVITE = "group_invite";
|
|
|
250
247
|
export declare const NOTIFY_JOIN_APPROVED = "join_approved";
|
|
251
248
|
export declare const NOTIFY_JOIN_REJECTED = "join_rejected";
|
|
252
249
|
export declare const NOTIFY_JOIN_REQUEST_RECEIVED = "join_request_received";
|
|
253
|
-
export declare const NOTIFY_GROUP_MESSAGE = "group_message";
|
|
254
250
|
export declare const NOTIFY_GROUP_EVENT = "group_event";
|
|
255
251
|
export declare const EVENT_MEMBER_JOINED = "member_joined";
|
|
256
252
|
export declare const EVENT_MEMBER_REMOVED = "member_removed";
|
|
@@ -267,3 +263,10 @@ export declare const EVENT_MEMBER_UNBANNED = "member_unbanned";
|
|
|
267
263
|
export declare const EVENT_JOIN_REQUIREMENTS_UPDATED = "join_requirements_updated";
|
|
268
264
|
export declare const EVENT_INVITE_CODE_CREATED = "invite_code_created";
|
|
269
265
|
export declare const EVENT_INVITE_CODE_REVOKED = "invite_code_revoked";
|
|
266
|
+
export declare const ACTION_MESSAGE_BATCH_PUSH = "message_batch_push";
|
|
267
|
+
export interface GroupMessageBatch {
|
|
268
|
+
messages: GroupMessage[];
|
|
269
|
+
start_msg_id: number;
|
|
270
|
+
latest_msg_id: number;
|
|
271
|
+
count: number;
|
|
272
|
+
}
|
package/dist/group/types.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Mirrors Python SDK: agentcp/group/types.py
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.EVENT_INVITE_CODE_REVOKED = exports.EVENT_INVITE_CODE_CREATED = exports.EVENT_JOIN_REQUIREMENTS_UPDATED = exports.EVENT_MEMBER_UNBANNED = exports.EVENT_GROUP_RESUMED = exports.EVENT_GROUP_SUSPENDED = exports.EVENT_MASTER_TRANSFERRED = exports.EVENT_GROUP_DISSOLVED = exports.EVENT_ANNOUNCEMENT_UPDATED = exports.EVENT_RULES_UPDATED = exports.EVENT_META_UPDATED = exports.EVENT_MEMBER_BANNED = exports.EVENT_MEMBER_LEFT = exports.EVENT_MEMBER_REMOVED = exports.EVENT_MEMBER_JOINED = exports.NOTIFY_GROUP_EVENT = exports.
|
|
7
|
+
exports.ACTION_MESSAGE_BATCH_PUSH = exports.EVENT_INVITE_CODE_REVOKED = exports.EVENT_INVITE_CODE_CREATED = exports.EVENT_JOIN_REQUIREMENTS_UPDATED = exports.EVENT_MEMBER_UNBANNED = exports.EVENT_GROUP_RESUMED = exports.EVENT_GROUP_SUSPENDED = exports.EVENT_MASTER_TRANSFERRED = exports.EVENT_GROUP_DISSOLVED = exports.EVENT_ANNOUNCEMENT_UPDATED = exports.EVENT_RULES_UPDATED = exports.EVENT_META_UPDATED = exports.EVENT_MEMBER_BANNED = exports.EVENT_MEMBER_LEFT = exports.EVENT_MEMBER_REMOVED = exports.EVENT_MEMBER_JOINED = exports.NOTIFY_GROUP_EVENT = exports.NOTIFY_JOIN_REQUEST_RECEIVED = exports.NOTIFY_JOIN_REJECTED = exports.NOTIFY_JOIN_APPROVED = exports.NOTIFY_GROUP_INVITE = exports.NOTIFY_NEW_EVENT = exports.NOTIFY_NEW_MESSAGE = exports.GroupError = exports.GroupErrorCode = void 0;
|
|
8
8
|
exports.buildGroupRequest = buildGroupRequest;
|
|
9
9
|
exports.groupRequestToJson = groupRequestToJson;
|
|
10
10
|
exports.parseGroupResponse = parseGroupResponse;
|
|
@@ -120,7 +120,6 @@ exports.NOTIFY_GROUP_INVITE = "group_invite";
|
|
|
120
120
|
exports.NOTIFY_JOIN_APPROVED = "join_approved";
|
|
121
121
|
exports.NOTIFY_JOIN_REJECTED = "join_rejected";
|
|
122
122
|
exports.NOTIFY_JOIN_REQUEST_RECEIVED = "join_request_received";
|
|
123
|
-
exports.NOTIFY_GROUP_MESSAGE = "group_message";
|
|
124
123
|
exports.NOTIFY_GROUP_EVENT = "group_event";
|
|
125
124
|
// Group Event Type Constants
|
|
126
125
|
exports.EVENT_MEMBER_JOINED = "member_joined";
|
|
@@ -138,3 +137,7 @@ exports.EVENT_MEMBER_UNBANNED = "member_unbanned";
|
|
|
138
137
|
exports.EVENT_JOIN_REQUIREMENTS_UPDATED = "join_requirements_updated";
|
|
139
138
|
exports.EVENT_INVITE_CODE_CREATED = "invite_code_created";
|
|
140
139
|
exports.EVENT_INVITE_CODE_REVOKED = "invite_code_revoked";
|
|
140
|
+
// ============================================================
|
|
141
|
+
// Batch Push Constants & Types
|
|
142
|
+
// ============================================================
|
|
143
|
+
exports.ACTION_MESSAGE_BATCH_PUSH = "message_batch_push";
|
package/dist/server.js
CHANGED
|
@@ -304,8 +304,6 @@ async function ensureGroupClient(instance) {
|
|
|
304
304
|
}
|
|
305
305
|
catch (_) { }
|
|
306
306
|
instance.agentCP.addGroupToStore(groupId, groupName);
|
|
307
|
-
const groupUrl = groupAddress || `https://${instance.groupTargetAid}/${groupId}`;
|
|
308
|
-
await instance.agentCP.registerGroupToHomeAP(groupId, groupUrl);
|
|
309
307
|
// 新加入的群也立即注册在线
|
|
310
308
|
await instance.agentCP.joinGroupSession(groupId);
|
|
311
309
|
}
|
|
@@ -327,19 +325,18 @@ async function ensureGroupClient(instance) {
|
|
|
327
325
|
console.log(`[Group] onJoinRequestReceived: group=${groupId} agent=${agentId} msg=${message}`);
|
|
328
326
|
broadcastToBrowser({ type: 'join_request', group_id: groupId, agent_id: agentId, message });
|
|
329
327
|
},
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
(_a = instance.agentCP.groupOps) === null || _a === void 0 ? void 0 : _a.ackMessages(instance.groupTargetAid, groupId, msg.msg_id).catch(e => {
|
|
336
|
-
console.warn(`[Group] auto ack failed: group=${groupId} msgId=${msg.msg_id}`, e.message || e);
|
|
337
|
-
});
|
|
338
|
-
// 推送给浏览器
|
|
328
|
+
onGroupMessageBatch(groupId, batch) {
|
|
329
|
+
console.log(`[Group] onGroupMessageBatch: group=${groupId} count=${batch.count} range=[${batch.start_msg_id}, ${batch.latest_msg_id}]`);
|
|
330
|
+
// 存储 + ACK(统一由 agentcp 处理)
|
|
331
|
+
const sorted = instance.agentCP.processAndAckBatch(groupId, batch);
|
|
332
|
+
// 推送消息列表给浏览器
|
|
339
333
|
broadcastToBrowser({
|
|
340
|
-
type: '
|
|
334
|
+
type: 'group_message_batch',
|
|
341
335
|
group_id: groupId,
|
|
342
|
-
|
|
336
|
+
messages: sorted,
|
|
337
|
+
count: batch.count,
|
|
338
|
+
start_msg_id: batch.start_msg_id,
|
|
339
|
+
latest_msg_id: batch.latest_msg_id,
|
|
343
340
|
});
|
|
344
341
|
},
|
|
345
342
|
onGroupEvent(groupId, evt) {
|
|
@@ -1667,6 +1664,24 @@ const chatHtml = `<!DOCTYPE html>
|
|
|
1667
1664
|
renderGroupMsgs(_lastGroupMsgs);
|
|
1668
1665
|
}
|
|
1669
1666
|
}
|
|
1667
|
+
} else if(data.type==='group_message_batch'){
|
|
1668
|
+
// 批量推送的消息列表
|
|
1669
|
+
var gid=data.group_id;
|
|
1670
|
+
var msgs=data.messages||[];
|
|
1671
|
+
if(gid===S.activeGroupId&&S.tab==='group'){
|
|
1672
|
+
var changed=false;
|
|
1673
|
+
msgs.forEach(function(msg){
|
|
1674
|
+
var exists=_lastGroupMsgs.some(function(m){ return m.msg_id===msg.msg_id; });
|
|
1675
|
+
if(!exists){
|
|
1676
|
+
_lastGroupMsgs.push(msg);
|
|
1677
|
+
changed=true;
|
|
1678
|
+
}
|
|
1679
|
+
});
|
|
1680
|
+
if(changed){
|
|
1681
|
+
_lastGroupMsgSig=''; // 强制重新渲染
|
|
1682
|
+
renderGroupMsgs(_lastGroupMsgs);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1670
1685
|
} else if(data.type==='new_message_notify'){
|
|
1671
1686
|
// 轻量通知:如果是当前活跃群组,拉取最新消息(本地读取,很快)
|
|
1672
1687
|
if(data.group_id===S.activeGroupId&&S.tab==='group'){
|
|
@@ -2676,9 +2691,6 @@ async function handleRequest(req, res) {
|
|
|
2676
2691
|
}
|
|
2677
2692
|
catch (_) { }
|
|
2678
2693
|
instance.agentCP.addGroupToStore(groupId, groupName);
|
|
2679
|
-
// 注册到 Home AP
|
|
2680
|
-
const registrationUrl = `https://${targetAid}/${groupId}`;
|
|
2681
|
-
await instance.agentCP.registerGroupToHomeAP(groupId, registrationUrl);
|
|
2682
2694
|
sendJson(res, { success: true, group_id: groupId });
|
|
2683
2695
|
}
|
|
2684
2696
|
else {
|