acp-ts 1.2.2 → 1.2.4
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.js +40 -33
- package/dist/agentws.d.ts +8 -2
- package/dist/agentws.js +22 -4
- package/dist/api.js +8 -8
- package/dist/cert.js +3 -2
- package/dist/cli.js +16 -15
- package/dist/datamanager.js +27 -11
- package/dist/filesync.js +11 -10
- package/dist/group/client.js +44 -36
- package/dist/group/cursor_store.d.ts +4 -9
- package/dist/group/cursor_store.js +12 -40
- package/dist/group/events.d.ts +2 -1
- package/dist/group/events.js +7 -3
- package/dist/group/index.d.ts +1 -1
- package/dist/group/index.js +2 -1
- package/dist/group/message_store.d.ts +5 -6
- package/dist/group/message_store.js +64 -72
- package/dist/group/operations.d.ts +24 -6
- package/dist/group/operations.js +55 -6
- package/dist/group/types.d.ts +30 -1
- package/dist/group/types.js +11 -1
- package/dist/heartbeat.js +24 -24
- package/dist/messagestore.js +9 -8
- package/dist/server.js +2288 -1661
- package/dist/utils.d.ts +6 -0
- package/dist/utils.js +19 -2
- package/dist/websocket.d.ts +12 -1
- package/dist/websocket.js +61 -28
- package/package.json +1 -1
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.GroupMessageStore = void 0;
|
|
13
13
|
const websocket_1 = require("../websocket");
|
|
14
|
+
const utils_1 = require("../utils");
|
|
14
15
|
class GroupMessageStore {
|
|
15
16
|
constructor(options) {
|
|
16
17
|
var _a, _b;
|
|
17
18
|
this.ownerAid = '';
|
|
18
19
|
this.groups = new Map();
|
|
19
20
|
this._indexDirty = false;
|
|
20
|
-
this._flushIndexPromise = null;
|
|
21
21
|
this.persistMessages = options.persistMessages;
|
|
22
22
|
this.basePath = options.basePath;
|
|
23
23
|
this.maxMessagesPerGroup = (_a = options.maxMessagesPerGroup) !== null && _a !== void 0 ? _a : 5000;
|
|
@@ -44,12 +44,12 @@ class GroupMessageStore {
|
|
|
44
44
|
const path = require('path');
|
|
45
45
|
return path.join(this.getGroupDir(aid, groupId), 'events.jsonl');
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
ensureDir(dir) {
|
|
48
48
|
if (!websocket_1.isNodeEnvironment)
|
|
49
49
|
return;
|
|
50
50
|
const fs = require('fs');
|
|
51
51
|
if (!fs.existsSync(dir)) {
|
|
52
|
-
|
|
52
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
// ---- load ----
|
|
@@ -64,45 +64,41 @@ class GroupMessageStore {
|
|
|
64
64
|
if (!fs.existsSync(indexPath))
|
|
65
65
|
return;
|
|
66
66
|
try {
|
|
67
|
-
const raw =
|
|
67
|
+
const raw = fs.readFileSync(indexPath, 'utf-8');
|
|
68
68
|
const records = JSON.parse(raw);
|
|
69
69
|
if (!Array.isArray(records))
|
|
70
70
|
return;
|
|
71
71
|
for (const r of records) {
|
|
72
|
-
const messages =
|
|
73
|
-
const events =
|
|
72
|
+
const messages = this.readJsonl(this.getMessagesPath(ownerAid, r.groupId));
|
|
73
|
+
const events = this.readJsonl(this.getEventsPath(ownerAid, r.groupId));
|
|
74
74
|
this.groups.set(r.groupId, { record: r, messages, events });
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
catch (e) {
|
|
78
|
-
|
|
78
|
+
utils_1.logger.error('[GroupMessageStore] 加载索引失败:', e);
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
readJsonl(filePath) {
|
|
82
82
|
if (!websocket_1.isNodeEnvironment)
|
|
83
83
|
return [];
|
|
84
84
|
const fs = require('fs');
|
|
85
85
|
if (!fs.existsSync(filePath))
|
|
86
86
|
return [];
|
|
87
87
|
try {
|
|
88
|
-
const raw =
|
|
88
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
89
89
|
const items = [];
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
const l = lines[i].trim();
|
|
90
|
+
for (const line of raw.split('\n')) {
|
|
91
|
+
const l = line.trim();
|
|
93
92
|
if (!l)
|
|
94
93
|
continue;
|
|
95
94
|
try {
|
|
96
95
|
items.push(JSON.parse(l));
|
|
97
96
|
}
|
|
98
|
-
catch (
|
|
99
|
-
console.warn(`[GroupMessageStore] JSONL 解析失败 (${filePath} 行${i + 1}): ${l.substring(0, 80)}`, lineErr);
|
|
100
|
-
}
|
|
97
|
+
catch (_a) { }
|
|
101
98
|
}
|
|
102
99
|
return items;
|
|
103
100
|
}
|
|
104
|
-
catch (
|
|
105
|
-
console.warn(`[GroupMessageStore] 读取 JSONL 文件失败 (${filePath}):`, e);
|
|
101
|
+
catch (_b) {
|
|
106
102
|
return [];
|
|
107
103
|
}
|
|
108
104
|
}
|
|
@@ -119,7 +115,7 @@ class GroupMessageStore {
|
|
|
119
115
|
data = { record, messages: [], events: [] };
|
|
120
116
|
this.groups.set(groupId, data);
|
|
121
117
|
this._indexDirty = true;
|
|
122
|
-
this.
|
|
118
|
+
this.flushIndexAsync();
|
|
123
119
|
}
|
|
124
120
|
return data.record;
|
|
125
121
|
}
|
|
@@ -147,17 +143,18 @@ class GroupMessageStore {
|
|
|
147
143
|
}
|
|
148
144
|
}
|
|
149
145
|
catch (e) {
|
|
150
|
-
|
|
146
|
+
utils_1.logger.error(`[GroupMessageStore] 删除群目录失败 (${groupId}):`, e);
|
|
151
147
|
}
|
|
152
148
|
await this.flushIndex();
|
|
153
149
|
}
|
|
154
150
|
return true;
|
|
155
151
|
}
|
|
156
152
|
// ---- message storage ----
|
|
157
|
-
|
|
153
|
+
addMessage(groupId, msg) {
|
|
158
154
|
const data = this.groups.get(groupId);
|
|
159
155
|
if (!data)
|
|
160
156
|
return;
|
|
157
|
+
// dedup: skip if msg_id already seen
|
|
161
158
|
if (msg.msg_id <= data.record.lastMsgId)
|
|
162
159
|
return;
|
|
163
160
|
data.messages.push(msg);
|
|
@@ -165,35 +162,37 @@ class GroupMessageStore {
|
|
|
165
162
|
data.record.messageCount = data.messages.length;
|
|
166
163
|
data.record.lastMessageAt = msg.timestamp || Date.now();
|
|
167
164
|
this._indexDirty = true;
|
|
165
|
+
// truncate if over limit
|
|
168
166
|
if (data.messages.length > this.maxMessagesPerGroup) {
|
|
169
167
|
const excess = data.messages.length - this.maxMessagesPerGroup;
|
|
170
168
|
data.messages.splice(0, excess);
|
|
171
169
|
data.record.messageCount = data.messages.length;
|
|
172
|
-
|
|
170
|
+
this.flushMessages(groupId);
|
|
173
171
|
}
|
|
174
172
|
else {
|
|
175
|
-
|
|
173
|
+
this.appendJsonl(this.getMessagesPath(this.ownerAid, groupId), msg);
|
|
176
174
|
}
|
|
177
|
-
this.
|
|
175
|
+
this.flushIndexAsync();
|
|
178
176
|
}
|
|
179
|
-
|
|
177
|
+
addMessages(groupId, msgs) {
|
|
180
178
|
const data = this.groups.get(groupId);
|
|
181
|
-
if (!data)
|
|
179
|
+
if (!data) {
|
|
180
|
+
utils_1.logger.warn(`[GroupMessageStore] addMessages: group=${groupId} NOT FOUND in store! Available groups: [${Array.from(this.groups.keys()).join(', ')}]`);
|
|
182
181
|
return;
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
}
|
|
183
|
+
utils_1.logger.log(`[GroupMessageStore] addMessages: group=${groupId} incoming=${msgs.length} currentLastMsgId=${data.record.lastMsgId} incomingMsgIds=[${msgs.map(m => m.msg_id).join(',')}]`);
|
|
185
184
|
let added = 0;
|
|
186
|
-
for (const msg of
|
|
187
|
-
if (
|
|
185
|
+
for (const msg of msgs) {
|
|
186
|
+
if (msg.msg_id <= data.record.lastMsgId) {
|
|
187
|
+
utils_1.logger.log(`[GroupMessageStore] addMessages: SKIP duplicate msg_id=${msg.msg_id} <= lastMsgId=${data.record.lastMsgId}`);
|
|
188
188
|
continue;
|
|
189
|
-
data.messages.push(msg);
|
|
190
|
-
existingIds.add(msg.msg_id);
|
|
191
|
-
if (msg.msg_id > data.record.lastMsgId) {
|
|
192
|
-
data.record.lastMsgId = msg.msg_id;
|
|
193
189
|
}
|
|
190
|
+
data.messages.push(msg);
|
|
191
|
+
data.record.lastMsgId = msg.msg_id;
|
|
194
192
|
data.record.lastMessageAt = msg.timestamp || Date.now();
|
|
195
193
|
added++;
|
|
196
194
|
}
|
|
195
|
+
utils_1.logger.log(`[GroupMessageStore] addMessages result: group=${groupId} added=${added}/${msgs.length} newLastMsgId=${data.record.lastMsgId} totalMessages=${data.messages.length}`);
|
|
197
196
|
if (added === 0)
|
|
198
197
|
return;
|
|
199
198
|
data.record.messageCount = data.messages.length;
|
|
@@ -202,9 +201,12 @@ class GroupMessageStore {
|
|
|
202
201
|
const excess = data.messages.length - this.maxMessagesPerGroup;
|
|
203
202
|
data.messages.splice(0, excess);
|
|
204
203
|
data.record.messageCount = data.messages.length;
|
|
204
|
+
this.flushMessages(groupId);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
this.flushMessages(groupId);
|
|
205
208
|
}
|
|
206
|
-
|
|
207
|
-
this.flushIndexQueued();
|
|
209
|
+
this.flushIndexAsync();
|
|
208
210
|
}
|
|
209
211
|
getMessages(groupId, options) {
|
|
210
212
|
const data = this.groups.get(groupId);
|
|
@@ -229,7 +231,7 @@ class GroupMessageStore {
|
|
|
229
231
|
return data.messages.slice(-limit);
|
|
230
232
|
}
|
|
231
233
|
// ---- event storage ----
|
|
232
|
-
|
|
234
|
+
addEvent(groupId, evt) {
|
|
233
235
|
const data = this.groups.get(groupId);
|
|
234
236
|
if (!data)
|
|
235
237
|
return;
|
|
@@ -243,14 +245,14 @@ class GroupMessageStore {
|
|
|
243
245
|
const excess = data.events.length - this.maxEventsPerGroup;
|
|
244
246
|
data.events.splice(0, excess);
|
|
245
247
|
data.record.eventCount = data.events.length;
|
|
246
|
-
|
|
248
|
+
this.flushEvents(groupId);
|
|
247
249
|
}
|
|
248
250
|
else {
|
|
249
|
-
|
|
251
|
+
this.appendJsonl(this.getEventsPath(this.ownerAid, groupId), evt);
|
|
250
252
|
}
|
|
251
|
-
this.
|
|
253
|
+
this.flushIndexAsync();
|
|
252
254
|
}
|
|
253
|
-
|
|
255
|
+
addEvents(groupId, evts) {
|
|
254
256
|
const data = this.groups.get(groupId);
|
|
255
257
|
if (!data)
|
|
256
258
|
return;
|
|
@@ -271,8 +273,8 @@ class GroupMessageStore {
|
|
|
271
273
|
data.events.splice(0, excess);
|
|
272
274
|
data.record.eventCount = data.events.length;
|
|
273
275
|
}
|
|
274
|
-
|
|
275
|
-
this.
|
|
276
|
+
this.flushEvents(groupId);
|
|
277
|
+
this.flushIndexAsync();
|
|
276
278
|
}
|
|
277
279
|
getEvents(groupId, options) {
|
|
278
280
|
const data = this.groups.get(groupId);
|
|
@@ -288,54 +290,47 @@ class GroupMessageStore {
|
|
|
288
290
|
return result;
|
|
289
291
|
}
|
|
290
292
|
// ---- persistence ----
|
|
291
|
-
|
|
293
|
+
appendJsonl(filePath, item) {
|
|
292
294
|
if (!this.persistMessages || !websocket_1.isNodeEnvironment || !this.ownerAid)
|
|
293
295
|
return;
|
|
294
296
|
const fs = require('fs');
|
|
295
297
|
const path = require('path');
|
|
296
|
-
|
|
298
|
+
this.ensureDir(path.dirname(filePath));
|
|
297
299
|
try {
|
|
298
|
-
|
|
300
|
+
fs.appendFileSync(filePath, JSON.stringify(item) + '\n');
|
|
299
301
|
}
|
|
300
302
|
catch (e) {
|
|
301
|
-
|
|
303
|
+
utils_1.logger.error(`[GroupMessageStore] 追加写入失败 (${filePath}):`, e);
|
|
302
304
|
}
|
|
303
305
|
}
|
|
304
|
-
|
|
306
|
+
writeJsonl(filePath, items) {
|
|
305
307
|
if (!this.persistMessages || !websocket_1.isNodeEnvironment || !this.ownerAid)
|
|
306
308
|
return;
|
|
307
309
|
const fs = require('fs');
|
|
308
310
|
const path = require('path');
|
|
309
|
-
|
|
311
|
+
this.ensureDir(path.dirname(filePath));
|
|
310
312
|
try {
|
|
311
313
|
const lines = items.map(i => JSON.stringify(i)).join('\n');
|
|
312
|
-
|
|
313
|
-
const tmpPath = filePath + '.tmp';
|
|
314
|
-
await fs.promises.writeFile(tmpPath, content);
|
|
315
|
-
await fs.promises.rename(tmpPath, filePath);
|
|
314
|
+
fs.writeFileSync(filePath, lines ? lines + '\n' : '');
|
|
316
315
|
}
|
|
317
316
|
catch (e) {
|
|
318
|
-
|
|
317
|
+
utils_1.logger.error(`[GroupMessageStore] 全量写入失败 (${filePath}):`, e);
|
|
319
318
|
}
|
|
320
319
|
}
|
|
321
|
-
|
|
320
|
+
flushMessages(groupId) {
|
|
322
321
|
const data = this.groups.get(groupId);
|
|
323
322
|
if (!data || !this.ownerAid)
|
|
324
323
|
return;
|
|
325
|
-
|
|
324
|
+
this.writeJsonl(this.getMessagesPath(this.ownerAid, groupId), data.messages);
|
|
326
325
|
}
|
|
327
|
-
|
|
326
|
+
flushEvents(groupId) {
|
|
328
327
|
const data = this.groups.get(groupId);
|
|
329
328
|
if (!data || !this.ownerAid)
|
|
330
329
|
return;
|
|
331
|
-
|
|
330
|
+
this.writeJsonl(this.getEventsPath(this.ownerAid, groupId), data.events);
|
|
332
331
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
const prev = (_a = this._flushIndexPromise) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
336
|
-
this._flushIndexPromise = prev.then(() => this.flushIndex()).catch(e => {
|
|
337
|
-
console.error('[GroupMessageStore] 索引刷盘失败:', e);
|
|
338
|
-
});
|
|
332
|
+
flushIndexAsync() {
|
|
333
|
+
this.flushIndex().catch(() => { });
|
|
339
334
|
}
|
|
340
335
|
async flushIndex() {
|
|
341
336
|
if (!this.persistMessages || !websocket_1.isNodeEnvironment || !this.ownerAid)
|
|
@@ -344,18 +339,15 @@ class GroupMessageStore {
|
|
|
344
339
|
return;
|
|
345
340
|
const fs = require('fs');
|
|
346
341
|
const dir = this.getGroupsDir(this.ownerAid);
|
|
347
|
-
|
|
342
|
+
this.ensureDir(dir);
|
|
348
343
|
const records = Array.from(this.groups.values())
|
|
349
344
|
.map(d => d.record);
|
|
350
345
|
try {
|
|
351
|
-
|
|
352
|
-
const tmpPath = indexPath + '.tmp';
|
|
353
|
-
await fs.promises.writeFile(tmpPath, JSON.stringify(records, null, 2));
|
|
354
|
-
await fs.promises.rename(tmpPath, indexPath);
|
|
346
|
+
fs.writeFileSync(this.getIndexPath(this.ownerAid), JSON.stringify(records, null, 2));
|
|
355
347
|
this._indexDirty = false;
|
|
356
348
|
}
|
|
357
349
|
catch (e) {
|
|
358
|
-
|
|
350
|
+
utils_1.logger.error('[GroupMessageStore] 写入索引失败:', e);
|
|
359
351
|
}
|
|
360
352
|
}
|
|
361
353
|
async flush(ownerAid) {
|
|
@@ -363,9 +355,9 @@ class GroupMessageStore {
|
|
|
363
355
|
return;
|
|
364
356
|
this.ownerAid = ownerAid;
|
|
365
357
|
await this.flushIndex();
|
|
366
|
-
for (const [groupId] of this.groups) {
|
|
367
|
-
|
|
368
|
-
|
|
358
|
+
for (const [groupId, data] of this.groups) {
|
|
359
|
+
this.flushMessages(groupId);
|
|
360
|
+
this.flushEvents(groupId);
|
|
369
361
|
}
|
|
370
362
|
}
|
|
371
363
|
async flushAll() {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Mirrors Python SDK: agentcp/group/operations.py
|
|
4
4
|
*/
|
|
5
5
|
import { ACPGroupClient } from './client';
|
|
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';
|
|
6
|
+
import { CreateGroupResp, SendMessageResp, PullMessagesResp, PullEventsResp, CursorState, GroupInfoResp, BanlistResp, BatchReviewResp, PendingRequestsResp, RequestJoinResp, MembersResp, AdminsResp, RulesResp, AnnouncementResp, JoinRequirementsResp, MasterResp, InviteCodeResp, InviteCodeListResp, BroadcastLockResp, BroadcastPermissionResp, SyncStatusResp, SyncLogResp, ChecksumResp, PublicGroupInfoResp, SearchGroupsResp, DigestResp, ListMyGroupsResp, GetFileResp, GetSummaryResp, GetMetricsResp, DutyConfig, DutyStatusResp } from './types';
|
|
7
7
|
/**
|
|
8
8
|
* Callback interface for syncGroup.
|
|
9
9
|
*/
|
|
@@ -30,18 +30,20 @@ export declare class GroupOperations {
|
|
|
30
30
|
/**
|
|
31
31
|
* 通过群聊链接加入群组。
|
|
32
32
|
* - 提供 inviteCode 时:免审核,直接通过邀请码加入
|
|
33
|
-
* - 不提供 inviteCode
|
|
33
|
+
* - 不提供 inviteCode 时:
|
|
34
|
+
* - 公开群:直接加入,返回 status="joined"
|
|
35
|
+
* - 私密群:提交加入申请,返回 status="pending"
|
|
34
36
|
*
|
|
35
37
|
* @param groupUrl 群聊链接,如 "https://group.agentcp.io/<group_id>"
|
|
36
38
|
* @param options 可选参数
|
|
37
39
|
* @param options.inviteCode 邀请码(免审核加入)
|
|
38
|
-
* @param options.message
|
|
39
|
-
* @returns
|
|
40
|
+
* @param options.message 申请消息(私密群审核模式下使用)
|
|
41
|
+
* @returns RequestJoinResp,包含 status 和 request_id
|
|
40
42
|
*/
|
|
41
43
|
joinByUrl(groupUrl: string, options?: {
|
|
42
44
|
inviteCode?: string;
|
|
43
45
|
message?: string;
|
|
44
|
-
}): Promise<
|
|
46
|
+
}): Promise<RequestJoinResp>;
|
|
45
47
|
/**
|
|
46
48
|
* 注册上线,告知 group.ap 当前客户端在线,可以接收消息推送。
|
|
47
49
|
* 客户端每次启动或重新连接时调用一次即可。
|
|
@@ -85,7 +87,7 @@ export declare class GroupOperations {
|
|
|
85
87
|
banAgent(targetAid: string, groupId: string, agentId: string, reason?: string, expiresAt?: number): Promise<void>;
|
|
86
88
|
unbanAgent(targetAid: string, groupId: string, agentId: string): Promise<void>;
|
|
87
89
|
getBanlist(targetAid: string, groupId: string): Promise<BanlistResp>;
|
|
88
|
-
requestJoin(targetAid: string, groupId: string, message?: string): Promise<
|
|
90
|
+
requestJoin(targetAid: string, groupId: string, message?: string): Promise<RequestJoinResp>;
|
|
89
91
|
reviewJoinRequest(targetAid: string, groupId: string, agentId: string, action: string, reason?: string): Promise<void>;
|
|
90
92
|
batchReviewJoinRequests(targetAid: string, groupId: string, agentIds: string[], action: string, reason?: string): Promise<BatchReviewResp>;
|
|
91
93
|
getPendingRequests(targetAid: string, groupId: string): Promise<PendingRequestsResp>;
|
|
@@ -132,4 +134,20 @@ export declare class GroupOperations {
|
|
|
132
134
|
getFile(targetAid: string, groupId: string, file: string, offset?: number): Promise<GetFileResp>;
|
|
133
135
|
getSummary(targetAid: string, groupId: string, date: string): Promise<GetSummaryResp>;
|
|
134
136
|
getMetrics(targetAid: string): Promise<GetMetricsResp>;
|
|
137
|
+
/**
|
|
138
|
+
* 更新值班配置。权限要求:creator 或 admin。
|
|
139
|
+
*/
|
|
140
|
+
updateDutyConfig(targetAid: string, groupId: string, config: Partial<DutyConfig>): Promise<void>;
|
|
141
|
+
/**
|
|
142
|
+
* 快捷设置固定值班 Agent 列表(自动切换为 fixed 模式)。
|
|
143
|
+
*/
|
|
144
|
+
setFixedAgents(targetAid: string, groupId: string, agents: string[]): Promise<void>;
|
|
145
|
+
/**
|
|
146
|
+
* 获取值班状态,包含 config 和 state。
|
|
147
|
+
*/
|
|
148
|
+
getDutyStatus(targetAid: string, groupId: string): Promise<DutyStatusResp>;
|
|
149
|
+
/**
|
|
150
|
+
* 重新获取所有成员的 agent.md 并更新 AgentType。
|
|
151
|
+
*/
|
|
152
|
+
refreshMemberTypes(targetAid: string, groupId: string): Promise<void>;
|
|
135
153
|
}
|
package/dist/group/operations.js
CHANGED
|
@@ -41,20 +41,22 @@ class GroupOperations {
|
|
|
41
41
|
/**
|
|
42
42
|
* 通过群聊链接加入群组。
|
|
43
43
|
* - 提供 inviteCode 时:免审核,直接通过邀请码加入
|
|
44
|
-
* - 不提供 inviteCode
|
|
44
|
+
* - 不提供 inviteCode 时:
|
|
45
|
+
* - 公开群:直接加入,返回 status="joined"
|
|
46
|
+
* - 私密群:提交加入申请,返回 status="pending"
|
|
45
47
|
*
|
|
46
48
|
* @param groupUrl 群聊链接,如 "https://group.agentcp.io/<group_id>"
|
|
47
49
|
* @param options 可选参数
|
|
48
50
|
* @param options.inviteCode 邀请码(免审核加入)
|
|
49
|
-
* @param options.message
|
|
50
|
-
* @returns
|
|
51
|
+
* @param options.message 申请消息(私密群审核模式下使用)
|
|
52
|
+
* @returns RequestJoinResp,包含 status 和 request_id
|
|
51
53
|
*/
|
|
52
54
|
async joinByUrl(groupUrl, options) {
|
|
53
55
|
var _a;
|
|
54
56
|
const { targetAid, groupId } = GroupOperations.parseGroupUrl(groupUrl);
|
|
55
57
|
if (options === null || options === void 0 ? void 0 : options.inviteCode) {
|
|
56
58
|
await this.useInviteCode(targetAid, groupId, options.inviteCode);
|
|
57
|
-
return '';
|
|
59
|
+
return { status: 'joined', request_id: '' };
|
|
58
60
|
}
|
|
59
61
|
return this.requestJoin(targetAid, groupId, (_a = options === null || options === void 0 ? void 0 : options.message) !== null && _a !== void 0 ? _a : '');
|
|
60
62
|
}
|
|
@@ -268,14 +270,14 @@ class GroupOperations {
|
|
|
268
270
|
return { banned: (_a = d.banned) !== null && _a !== void 0 ? _a : [] };
|
|
269
271
|
}
|
|
270
272
|
async requestJoin(targetAid, groupId, message = "") {
|
|
271
|
-
var _a;
|
|
273
|
+
var _a, _b;
|
|
272
274
|
const params = {};
|
|
273
275
|
if (message)
|
|
274
276
|
params.message = message;
|
|
275
277
|
const resp = await this._client.sendRequest(targetAid, groupId, "request_join", Object.keys(params).length > 0 ? params : null);
|
|
276
278
|
this._check(resp, "request_join");
|
|
277
279
|
const d = resp.data || {};
|
|
278
|
-
return (_a = d.
|
|
280
|
+
return { status: (_a = d.status) !== null && _a !== void 0 ? _a : "pending", request_id: (_b = d.request_id) !== null && _b !== void 0 ? _b : "" };
|
|
279
281
|
}
|
|
280
282
|
async reviewJoinRequest(targetAid, groupId, agentId, action, reason = "") {
|
|
281
283
|
const params = { agent_id: agentId, action };
|
|
@@ -616,5 +618,52 @@ class GroupOperations {
|
|
|
616
618
|
sys_mb: (_c = d.sys_mb) !== null && _c !== void 0 ? _c : 0, gc_cycles: (_d = d.gc_cycles) !== null && _d !== void 0 ? _d : 0,
|
|
617
619
|
};
|
|
618
620
|
}
|
|
621
|
+
// ============================================================
|
|
622
|
+
// Duty (值班) Operations
|
|
623
|
+
// ============================================================
|
|
624
|
+
/**
|
|
625
|
+
* 更新值班配置。权限要求:creator 或 admin。
|
|
626
|
+
*/
|
|
627
|
+
async updateDutyConfig(targetAid, groupId, config) {
|
|
628
|
+
const params = {};
|
|
629
|
+
if (config.mode != null)
|
|
630
|
+
params.mode = config.mode;
|
|
631
|
+
if (config.rotation_strategy != null)
|
|
632
|
+
params.rotation_strategy = config.rotation_strategy;
|
|
633
|
+
if (config.shift_duration_ms != null)
|
|
634
|
+
params.shift_duration_ms = config.shift_duration_ms;
|
|
635
|
+
if (config.max_messages_per_shift != null)
|
|
636
|
+
params.max_messages_per_shift = config.max_messages_per_shift;
|
|
637
|
+
if (config.duty_priority_window_ms != null)
|
|
638
|
+
params.duty_priority_window_ms = config.duty_priority_window_ms;
|
|
639
|
+
if (config.enable_rule_prelude != null)
|
|
640
|
+
params.enable_rule_prelude = config.enable_rule_prelude;
|
|
641
|
+
const resp = await this._client.sendRequest(targetAid, groupId, "update_duty_config", { duty_config: params });
|
|
642
|
+
this._check(resp, "update_duty_config");
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* 快捷设置固定值班 Agent 列表(自动切换为 fixed 模式)。
|
|
646
|
+
*/
|
|
647
|
+
async setFixedAgents(targetAid, groupId, agents) {
|
|
648
|
+
const resp = await this._client.sendRequest(targetAid, groupId, "set_fixed_agents", { agents });
|
|
649
|
+
this._check(resp, "set_fixed_agents");
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* 获取值班状态,包含 config 和 state。
|
|
653
|
+
*/
|
|
654
|
+
async getDutyStatus(targetAid, groupId) {
|
|
655
|
+
var _a, _b;
|
|
656
|
+
const resp = await this._client.sendRequest(targetAid, groupId, "get_duty_status", null);
|
|
657
|
+
this._check(resp, "get_duty_status");
|
|
658
|
+
const d = resp.data || {};
|
|
659
|
+
return { config: (_a = d.config) !== null && _a !== void 0 ? _a : {}, state: (_b = d.state) !== null && _b !== void 0 ? _b : {} };
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* 重新获取所有成员的 agent.md 并更新 AgentType。
|
|
663
|
+
*/
|
|
664
|
+
async refreshMemberTypes(targetAid, groupId) {
|
|
665
|
+
const resp = await this._client.sendRequest(targetAid, groupId, "refresh_member_types", null);
|
|
666
|
+
this._check(resp, "refresh_member_types");
|
|
667
|
+
}
|
|
619
668
|
}
|
|
620
669
|
exports.GroupOperations = GroupOperations;
|
package/dist/group/types.d.ts
CHANGED
|
@@ -17,7 +17,11 @@ export declare enum GroupErrorCode {
|
|
|
17
17
|
INVITE_CODE_INVALID = 1011,
|
|
18
18
|
REQUEST_EXISTS = 1012,
|
|
19
19
|
BROADCAST_CONFLICT = 1013,
|
|
20
|
-
ACTION_NOT_IMPL = 1099
|
|
20
|
+
ACTION_NOT_IMPL = 1099,
|
|
21
|
+
DUTY_NOT_ENABLED = 1020,
|
|
22
|
+
NOT_DUTY_AGENT = 1021,
|
|
23
|
+
AGENT_MD_NOT_FOUND = 1024,
|
|
24
|
+
AGENT_MD_INVALID = 1025
|
|
21
25
|
}
|
|
22
26
|
export declare class GroupError extends Error {
|
|
23
27
|
action: string;
|
|
@@ -120,6 +124,11 @@ export interface GroupInfoResp {
|
|
|
120
124
|
export interface BanlistResp {
|
|
121
125
|
banned: Record<string, any>[];
|
|
122
126
|
}
|
|
127
|
+
export interface RequestJoinResp {
|
|
128
|
+
/** "joined" = 已直接加入(公开群), "pending" = 等待审核(私密群) */
|
|
129
|
+
status: string;
|
|
130
|
+
request_id: string;
|
|
131
|
+
}
|
|
123
132
|
export interface BatchReviewResp {
|
|
124
133
|
processed: number;
|
|
125
134
|
total: number;
|
|
@@ -247,6 +256,7 @@ export declare const NOTIFY_GROUP_INVITE = "group_invite";
|
|
|
247
256
|
export declare const NOTIFY_JOIN_APPROVED = "join_approved";
|
|
248
257
|
export declare const NOTIFY_JOIN_REJECTED = "join_rejected";
|
|
249
258
|
export declare const NOTIFY_JOIN_REQUEST_RECEIVED = "join_request_received";
|
|
259
|
+
export declare const NOTIFY_GROUP_MESSAGE = "group_message";
|
|
250
260
|
export declare const NOTIFY_GROUP_EVENT = "group_event";
|
|
251
261
|
export declare const EVENT_MEMBER_JOINED = "member_joined";
|
|
252
262
|
export declare const EVENT_MEMBER_REMOVED = "member_removed";
|
|
@@ -263,6 +273,25 @@ export declare const EVENT_MEMBER_UNBANNED = "member_unbanned";
|
|
|
263
273
|
export declare const EVENT_JOIN_REQUIREMENTS_UPDATED = "join_requirements_updated";
|
|
264
274
|
export declare const EVENT_INVITE_CODE_CREATED = "invite_code_created";
|
|
265
275
|
export declare const EVENT_INVITE_CODE_REVOKED = "invite_code_revoked";
|
|
276
|
+
export interface DutyConfig {
|
|
277
|
+
mode: "none" | "fixed" | "rotation";
|
|
278
|
+
rotation_strategy?: "round_robin" | "random";
|
|
279
|
+
shift_duration_ms?: number;
|
|
280
|
+
max_messages_per_shift?: number;
|
|
281
|
+
duty_priority_window_ms?: number;
|
|
282
|
+
enable_rule_prelude?: boolean;
|
|
283
|
+
agents?: string[];
|
|
284
|
+
}
|
|
285
|
+
export interface DutyState {
|
|
286
|
+
current_duty_agent?: string;
|
|
287
|
+
shift_start_time?: number;
|
|
288
|
+
messages_in_shift?: number;
|
|
289
|
+
[key: string]: any;
|
|
290
|
+
}
|
|
291
|
+
export interface DutyStatusResp {
|
|
292
|
+
config: DutyConfig;
|
|
293
|
+
state: DutyState;
|
|
294
|
+
}
|
|
266
295
|
export declare const ACTION_MESSAGE_BATCH_PUSH = "message_batch_push";
|
|
267
296
|
export interface GroupMessageBatch {
|
|
268
297
|
messages: GroupMessage[];
|
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.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;
|
|
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_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.GroupError = exports.GroupErrorCode = void 0;
|
|
8
8
|
exports.buildGroupRequest = buildGroupRequest;
|
|
9
9
|
exports.groupRequestToJson = groupRequestToJson;
|
|
10
10
|
exports.parseGroupResponse = parseGroupResponse;
|
|
@@ -31,6 +31,11 @@ var GroupErrorCode;
|
|
|
31
31
|
GroupErrorCode[GroupErrorCode["REQUEST_EXISTS"] = 1012] = "REQUEST_EXISTS";
|
|
32
32
|
GroupErrorCode[GroupErrorCode["BROADCAST_CONFLICT"] = 1013] = "BROADCAST_CONFLICT";
|
|
33
33
|
GroupErrorCode[GroupErrorCode["ACTION_NOT_IMPL"] = 1099] = "ACTION_NOT_IMPL";
|
|
34
|
+
// Duty error codes
|
|
35
|
+
GroupErrorCode[GroupErrorCode["DUTY_NOT_ENABLED"] = 1020] = "DUTY_NOT_ENABLED";
|
|
36
|
+
GroupErrorCode[GroupErrorCode["NOT_DUTY_AGENT"] = 1021] = "NOT_DUTY_AGENT";
|
|
37
|
+
GroupErrorCode[GroupErrorCode["AGENT_MD_NOT_FOUND"] = 1024] = "AGENT_MD_NOT_FOUND";
|
|
38
|
+
GroupErrorCode[GroupErrorCode["AGENT_MD_INVALID"] = 1025] = "AGENT_MD_INVALID";
|
|
34
39
|
})(GroupErrorCode || (exports.GroupErrorCode = GroupErrorCode = {}));
|
|
35
40
|
const CODE_MESSAGES = {
|
|
36
41
|
0: "success",
|
|
@@ -47,6 +52,10 @@ const CODE_MESSAGES = {
|
|
|
47
52
|
1011: "invite code invalid",
|
|
48
53
|
1012: "request exists",
|
|
49
54
|
1013: "broadcast conflict",
|
|
55
|
+
1020: "duty not enabled",
|
|
56
|
+
1021: "not duty agent",
|
|
57
|
+
1024: "agent.md not found",
|
|
58
|
+
1025: "agent.md invalid",
|
|
50
59
|
1099: "action not implemented",
|
|
51
60
|
};
|
|
52
61
|
class GroupError extends Error {
|
|
@@ -120,6 +129,7 @@ exports.NOTIFY_GROUP_INVITE = "group_invite";
|
|
|
120
129
|
exports.NOTIFY_JOIN_APPROVED = "join_approved";
|
|
121
130
|
exports.NOTIFY_JOIN_REJECTED = "join_rejected";
|
|
122
131
|
exports.NOTIFY_JOIN_REQUEST_RECEIVED = "join_request_received";
|
|
132
|
+
exports.NOTIFY_GROUP_MESSAGE = "group_message";
|
|
123
133
|
exports.NOTIFY_GROUP_EVENT = "group_event";
|
|
124
134
|
// Group Event Type Constants
|
|
125
135
|
exports.EVENT_MEMBER_JOINED = "member_joined";
|