acp-ts 1.1.9 → 1.2.1

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 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 } from "./group";
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
- * - onGroupMessage: 自动存储消息到 GroupMessageStore + 自动 ACK
93
+ * - onGroupMessageBatch: 自动存储消息 + watermark ACK
94
94
  * - onJoinApproved: 自动注册到 Home AP + 存储群组
95
95
  * 外部可通过 setGroupEventHandler 覆盖。
96
96
  */
97
97
  private _createDefaultGroupEventHandler;
98
98
  /**
99
- * 自动 ACK 消息(SDK 内部行为,对上层透明)
99
+ * 处理批量推送消息:排序、存储、ACK 最后一条。
100
+ * 返回排序后的消息列表,供上层使用(如推送给浏览器)。
100
101
  */
101
- private _autoAckMessage;
102
+ processAndAckBatch(groupId: string, batch: GroupMessageBatch): Promise<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
  */
@@ -157,11 +158,11 @@ declare class AgentCP implements IAgentCP {
157
158
  /**
158
159
  * 添加群消息到本地存储
159
160
  */
160
- addGroupMessageToStore(groupId: string, msg: GroupMessage): void;
161
+ addGroupMessageToStore(groupId: string, msg: GroupMessage): Promise<void>;
161
162
  /**
162
163
  * 批量添加群消息到本地存储
163
164
  */
164
- addGroupMessagesToStore(groupId: string, msgs: GroupMessage[]): void;
165
+ addGroupMessagesToStore(groupId: string, msgs: GroupMessage[]): Promise<void>;
165
166
  /**
166
167
  * 获取本地存储中群组的最新消息ID(用于增量拉取)
167
168
  */
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 = false;
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 : false;
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
- * - onGroupMessage: 自动存储消息到 GroupMessageStore + 自动 ACK
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,11 @@ class AgentCP {
445
443
  onJoinRequestReceived(groupId, agentId, message) {
446
444
  console.log(`[Group][DefaultHandler] onJoinRequestReceived: group=${groupId} agent=${agentId}`);
447
445
  },
448
- onGroupMessage: (groupId, msg) => {
449
- console.log(`[Group][DefaultHandler] onGroupMessage: group=${groupId} msgId=${msg.msg_id} sender=${msg.sender}`);
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).catch(e => {
449
+ console.error(`[Group][DefaultHandler] processAndAckBatch failed: group=${groupId}`, e);
450
+ });
454
451
  },
455
452
  onGroupEvent(groupId, evt) {
456
453
  console.log(`[Group][DefaultHandler] onGroupEvent: group=${groupId} event=${evt.event_type}`);
@@ -458,13 +455,27 @@ class AgentCP {
458
455
  };
459
456
  }
460
457
  /**
461
- * 自动 ACK 消息(SDK 内部行为,对上层透明)
458
+ * 处理批量推送消息:排序、存储、ACK 最后一条。
459
+ * 返回排序后的消息列表,供上层使用(如推送给浏览器)。
460
+ */
461
+ async processAndAckBatch(groupId, batch) {
462
+ const sorted = [...batch.messages].sort((a, b) => a.msg_id - b.msg_id);
463
+ await this.addGroupMessagesToStore(groupId, sorted);
464
+ // ACK batch 中最后一条消息
465
+ if (sorted.length > 0) {
466
+ const lastMsgId = sorted[sorted.length - 1].msg_id;
467
+ this._ackMessage(groupId, lastMsgId);
468
+ }
469
+ return sorted;
470
+ }
471
+ /**
472
+ * 异步 ACK 消息(不阻塞调用方)
462
473
  */
463
- _autoAckMessage(groupId, msgId) {
474
+ _ackMessage(groupId, msgId) {
464
475
  if (!this.groupOps || !this._groupTargetAid)
465
476
  return;
466
477
  this.groupOps.ackMessages(this._groupTargetAid, groupId, msgId).catch(e => {
467
- console.warn(`[Group] auto ack failed: group=${groupId} msgId=${msgId}`, e.message || e);
478
+ console.warn(`[Group] ack failed: group=${groupId} msgId=${msgId}`, e.message || e);
468
479
  });
469
480
  }
470
481
  /**
@@ -552,6 +563,17 @@ class AgentCP {
552
563
  this.groupMessageStore.getOrCreateGroup(membership.group_id, this._groupTargetAid, name);
553
564
  }
554
565
  }
566
+ // 清理本地有但服务端已不存在的群组
567
+ if (this.groupMessageStore) {
568
+ const serverGroupIds = new Set(result.groups.map(g => g.group_id));
569
+ const localGroups = this.groupMessageStore.getGroupList();
570
+ for (const local of localGroups) {
571
+ if (!serverGroupIds.has(local.groupId)) {
572
+ await this.groupMessageStore.deleteGroup(local.groupId);
573
+ console.log(`[Group] syncGroupList: 清理本地已退出群组 ${local.groupId}`);
574
+ }
575
+ }
576
+ }
555
577
  return groups;
556
578
  }
557
579
  /**
@@ -574,20 +596,6 @@ class AgentCP {
574
596
  return;
575
597
  this.groupMessageStore.getOrCreateGroup(groupId, this._groupTargetAid, name);
576
598
  }
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
599
  /**
592
600
  * 从本地存储删除群组
593
601
  */
@@ -610,18 +618,18 @@ class AgentCP {
610
618
  /**
611
619
  * 添加群消息到本地存储
612
620
  */
613
- addGroupMessageToStore(groupId, msg) {
621
+ async addGroupMessageToStore(groupId, msg) {
614
622
  if (!this.groupMessageStore)
615
623
  return;
616
- this.groupMessageStore.addMessage(groupId, msg);
624
+ await this.groupMessageStore.addMessage(groupId, msg);
617
625
  }
618
626
  /**
619
627
  * 批量添加群消息到本地存储
620
628
  */
621
- addGroupMessagesToStore(groupId, msgs) {
629
+ async addGroupMessagesToStore(groupId, msgs) {
622
630
  if (!this.groupMessageStore)
623
631
  return;
624
- this.groupMessageStore.addMessages(groupId, msgs);
632
+ await this.groupMessageStore.addMessages(groupId, msgs);
625
633
  }
626
634
  /**
627
635
  * 获取本地存储中群组的最新消息ID(用于增量拉取)
@@ -664,7 +672,7 @@ class AgentCP {
664
672
  metadata: (_f = m.metadata) !== null && _f !== void 0 ? _f : null,
665
673
  });
666
674
  });
667
- this.addGroupMessagesToStore(groupId, msgs);
675
+ await this.addGroupMessagesToStore(groupId, msgs);
668
676
  // ACK 这批消息中的最后一条
669
677
  const lastMsgId = msgs[msgs.length - 1].msg_id;
670
678
  await this.groupOps.ackMessages(this._groupTargetAid, groupId, lastMsgId);
@@ -697,7 +705,15 @@ class AgentCP {
697
705
  await this.groupOps.registerOnline(this._groupTargetAid);
698
706
  this._onlineGroups.add(groupId);
699
707
  console.log(`[Group] joinGroupSession: group=${groupId}`);
700
- // Step 2: 启动心跳定时器(首次加入群组时启动)
708
+ // Step 2: 冷启动同步 — 拉取历史消息对齐,再进入批推送接收
709
+ try {
710
+ const lastMsgId = this.getGroupLastMsgId(groupId);
711
+ await this.pullAndStoreGroupMessages(groupId, lastMsgId, 50);
712
+ }
713
+ catch (e) {
714
+ console.warn(`[Group] cold-start sync failed: group=${groupId}`, e.message || e);
715
+ }
716
+ // Step 3: 启动心跳定时器(首次加入群组时启动)
701
717
  this._ensureHeartbeat();
702
718
  }
703
719
  /**
@@ -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, _k, _l, _m;
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 action-based push messages from group.ap (e.g. message_push)
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 === "message_push" && data.data) {
123
- console.log(`[GroupClient] message_push -> group_message: group=${data.group_id} msg_id=${data.data.msg_id}`);
124
- const msgData = data.data;
125
- const notify = {
126
- action: "group_notify",
127
- group_id: (_e = data.group_id) !== null && _e !== void 0 ? _e : "",
128
- event: types_1.NOTIFY_GROUP_MESSAGE,
129
- data: {
130
- msg_id: (_f = msgData.msg_id) !== null && _f !== void 0 ? _f : 0,
131
- sender: (_g = msgData.sender) !== null && _g !== void 0 ? _g : "",
132
- content: (_h = msgData.content) !== null && _h !== void 0 ? _h : "",
133
- content_type: (_j = msgData.content_type) !== null && _j !== void 0 ? _j : "text",
134
- timestamp: (_k = msgData.timestamp) !== null && _k !== void 0 ? _k : 0,
135
- metadata: (_l = msgData.metadata) !== null && _l !== void 0 ? _l : null,
136
- },
137
- timestamp: (_m = msgData.timestamp) !== null && _m !== void 0 ? _m : 0,
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
- (0, events_1.dispatchAcpNotify)(this._handler, notify);
142
+ this._handler.onGroupMessageBatch(groupId, batch);
141
143
  }
142
144
  else {
143
- console.warn(`[GroupClient] !!! message_push dropped: no event handler registered.`);
145
+ console.warn(`[GroupClient] !!! message_batch_push dropped: no event handler registered.`);
144
146
  }
145
147
  return;
146
148
  }
@@ -158,7 +160,9 @@ class ACPGroupClient {
158
160
  this._pendingReqs.clear();
159
161
  if (this._cursorStore != null) {
160
162
  try {
161
- this._cursorStore.close();
163
+ this._cursorStore.close().catch(e => {
164
+ console.error("[ACPGroupClient] cursor store close error:", e);
165
+ });
162
166
  }
163
167
  catch (e) {
164
168
  console.error("[ACPGroupClient] cursor store close error:", e);
@@ -10,8 +10,8 @@ export interface CursorStore {
10
10
  saveEventCursor(groupId: string, eventCursor: number): void;
11
11
  loadCursor(groupId: string): [number, number];
12
12
  removeCursor(groupId: string): void;
13
- flush(): void;
14
- close(): void;
13
+ flush(): Promise<void>;
14
+ close(): Promise<void>;
15
15
  }
16
16
  /**
17
17
  * In-memory + JSON file cursor store.
@@ -24,13 +24,18 @@ export declare class LocalCursorStore implements CursorStore {
24
24
  private _cursors;
25
25
  private _filePath;
26
26
  private _dirty;
27
+ private _flushTimer;
28
+ private _flushPromise;
29
+ private _loaded;
27
30
  constructor(filePath?: string);
31
+ init(): Promise<void>;
28
32
  saveMsgCursor(groupId: string, msgCursor: number): void;
29
33
  saveEventCursor(groupId: string, eventCursor: number): void;
30
34
  loadCursor(groupId: string): [number, number];
31
35
  removeCursor(groupId: string): void;
32
- flush(): void;
33
- close(): void;
36
+ flush(): Promise<void>;
37
+ close(): Promise<void>;
38
+ private _flushDebounced;
34
39
  private _write;
35
40
  private _load;
36
41
  }
@@ -17,9 +17,15 @@ class LocalCursorStore {
17
17
  constructor(filePath = "") {
18
18
  this._cursors = {};
19
19
  this._dirty = false;
20
+ this._flushTimer = null;
21
+ this._flushPromise = null;
22
+ this._loaded = false;
20
23
  this._filePath = filePath;
21
- if (filePath && websocket_1.isNodeEnvironment) {
22
- this._load();
24
+ }
25
+ async init() {
26
+ if (this._filePath && websocket_1.isNodeEnvironment && !this._loaded) {
27
+ await this._load();
28
+ this._loaded = true;
23
29
  }
24
30
  }
25
31
  saveMsgCursor(groupId, msgCursor) {
@@ -29,6 +35,7 @@ class LocalCursorStore {
29
35
  if (msgCursor > this._cursors[groupId].msg_cursor) {
30
36
  this._cursors[groupId].msg_cursor = msgCursor;
31
37
  this._dirty = true;
38
+ this._flushDebounced();
32
39
  }
33
40
  }
34
41
  saveEventCursor(groupId, eventCursor) {
@@ -38,6 +45,7 @@ class LocalCursorStore {
38
45
  if (eventCursor > this._cursors[groupId].event_cursor) {
39
46
  this._cursors[groupId].event_cursor = eventCursor;
40
47
  this._dirty = true;
48
+ this._flushDebounced();
41
49
  }
42
50
  }
43
51
  loadCursor(groupId) {
@@ -51,37 +59,58 @@ class LocalCursorStore {
51
59
  if (groupId in this._cursors) {
52
60
  delete this._cursors[groupId];
53
61
  this._dirty = true;
62
+ this._flushDebounced();
54
63
  }
55
64
  }
56
- flush() {
65
+ async flush() {
57
66
  if (!this._filePath || !websocket_1.isNodeEnvironment) {
58
67
  return;
59
68
  }
60
69
  if (!this._dirty) {
61
70
  return;
62
71
  }
63
- this._write();
72
+ await this._write();
73
+ }
74
+ async close() {
75
+ if (this._flushTimer) {
76
+ clearTimeout(this._flushTimer);
77
+ this._flushTimer = null;
78
+ }
79
+ await this.flush();
64
80
  }
65
- close() {
66
- this.flush();
81
+ _flushDebounced() {
82
+ if (this._flushTimer)
83
+ return;
84
+ this._flushTimer = setTimeout(async () => {
85
+ this._flushTimer = null;
86
+ try {
87
+ await this.flush();
88
+ }
89
+ catch (e) {
90
+ console.error('[CursorStore] debounced flush failed:', e);
91
+ }
92
+ }, 500);
67
93
  }
68
- _write() {
94
+ async _write() {
69
95
  try {
70
96
  const fs = require('fs');
71
- fs.writeFileSync(this._filePath, JSON.stringify(this._cursors, null, 2), 'utf-8');
97
+ const content = JSON.stringify(this._cursors, null, 2);
98
+ const tmpPath = this._filePath + '.tmp';
99
+ await fs.promises.writeFile(tmpPath, content, 'utf-8');
100
+ await fs.promises.rename(tmpPath, this._filePath);
72
101
  this._dirty = false;
73
102
  }
74
103
  catch (e) {
75
104
  console.error(`[CursorStore] write to ${this._filePath} failed:`, e);
76
105
  }
77
106
  }
78
- _load() {
107
+ async _load() {
79
108
  try {
80
109
  const fs = require('fs');
81
110
  if (!fs.existsSync(this._filePath)) {
82
111
  return;
83
112
  }
84
- const content = fs.readFileSync(this._filePath, 'utf-8');
113
+ const content = await fs.promises.readFile(this._filePath, 'utf-8');
85
114
  if (content) {
86
115
  this._cursors = JSON.parse(content);
87
116
  }
@@ -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, GroupMessage, GroupEvent } from './types';
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
- onGroupMessage(groupId: string, msg: GroupMessage): void;
16
+ onGroupMessageBatch(groupId: string, batch: GroupMessageBatch): void;
17
17
  onGroupEvent(groupId: string, evt: GroupEvent): void;
18
18
  }
19
19
  /**
@@ -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
  }
@@ -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, 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_MESSAGE, 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, } from './types';
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';
@@ -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.NOTIFY_GROUP_MESSAGE = 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;
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; } });
@@ -27,6 +27,7 @@ export declare class GroupMessageStore {
27
27
  private maxEventsPerGroup;
28
28
  private groups;
29
29
  private _indexDirty;
30
+ private _flushIndexPromise;
30
31
  constructor(options: {
31
32
  persistMessages: boolean;
32
33
  basePath: string;
@@ -45,16 +46,16 @@ export declare class GroupMessageStore {
45
46
  getGroupList(): GroupRecord[];
46
47
  getGroup(groupId: string): GroupRecord | null;
47
48
  deleteGroup(groupId: string): Promise<boolean>;
48
- addMessage(groupId: string, msg: GroupMessage): void;
49
- addMessages(groupId: string, msgs: GroupMessage[]): void;
49
+ addMessage(groupId: string, msg: GroupMessage): Promise<void>;
50
+ addMessages(groupId: string, msgs: GroupMessage[]): Promise<void>;
50
51
  getMessages(groupId: string, options?: {
51
52
  afterMsgId?: number;
52
53
  beforeMsgId?: number;
53
54
  limit?: number;
54
55
  }): GroupMessage[];
55
56
  getLatestMessages(groupId: string, limit?: number): GroupMessage[];
56
- addEvent(groupId: string, evt: GroupEvent): void;
57
- addEvents(groupId: string, evts: GroupEvent[]): void;
57
+ addEvent(groupId: string, evt: GroupEvent): Promise<void>;
58
+ addEvents(groupId: string, evts: GroupEvent[]): Promise<void>;
58
59
  getEvents(groupId: string, options?: {
59
60
  afterEventId?: number;
60
61
  limit?: number;
@@ -63,7 +64,7 @@ export declare class GroupMessageStore {
63
64
  private writeJsonl;
64
65
  private flushMessages;
65
66
  private flushEvents;
66
- private flushIndexAsync;
67
+ private flushIndexQueued;
67
68
  flushIndex(): Promise<void>;
68
69
  flush(ownerAid: string): Promise<void>;
69
70
  flushAll(): Promise<void>;