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.
@@ -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
- async ensureDir(dir) {
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
- await fs.promises.mkdir(dir, { recursive: true });
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 = await fs.promises.readFile(indexPath, 'utf-8');
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 = await this.readJsonl(this.getMessagesPath(ownerAid, r.groupId));
73
- const events = await this.readJsonl(this.getEventsPath(ownerAid, r.groupId));
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
- console.error('[GroupMessageStore] 加载索引失败:', e);
78
+ utils_1.logger.error('[GroupMessageStore] 加载索引失败:', e);
79
79
  }
80
80
  }
81
- async readJsonl(filePath) {
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 = await fs.promises.readFile(filePath, 'utf-8');
88
+ const raw = fs.readFileSync(filePath, 'utf-8');
89
89
  const items = [];
90
- const lines = raw.split('\n');
91
- for (let i = 0; i < lines.length; i++) {
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 (lineErr) {
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 (e) {
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.flushIndexQueued();
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
- console.error(`[GroupMessageStore] 删除群目录失败 (${groupId}):`, e);
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
- async addMessage(groupId, msg) {
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
- await this.flushMessages(groupId);
170
+ this.flushMessages(groupId);
173
171
  }
174
172
  else {
175
- await this.appendJsonl(this.getMessagesPath(this.ownerAid, groupId), msg);
173
+ this.appendJsonl(this.getMessagesPath(this.ownerAid, groupId), msg);
176
174
  }
177
- this.flushIndexQueued();
175
+ this.flushIndexAsync();
178
176
  }
179
- async addMessages(groupId, msgs) {
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
- const sorted = [...msgs].sort((a, b) => a.msg_id - b.msg_id);
184
- const existingIds = new Set(data.messages.map(m => m.msg_id));
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 sorted) {
187
- if (existingIds.has(msg.msg_id))
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
- await this.flushMessages(groupId);
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
- async addEvent(groupId, evt) {
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
- await this.flushEvents(groupId);
248
+ this.flushEvents(groupId);
247
249
  }
248
250
  else {
249
- await this.appendJsonl(this.getEventsPath(this.ownerAid, groupId), evt);
251
+ this.appendJsonl(this.getEventsPath(this.ownerAid, groupId), evt);
250
252
  }
251
- this.flushIndexQueued();
253
+ this.flushIndexAsync();
252
254
  }
253
- async addEvents(groupId, evts) {
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
- await this.flushEvents(groupId);
275
- this.flushIndexQueued();
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
- async appendJsonl(filePath, item) {
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
- await this.ensureDir(path.dirname(filePath));
298
+ this.ensureDir(path.dirname(filePath));
297
299
  try {
298
- await fs.promises.appendFile(filePath, JSON.stringify(item) + '\n');
300
+ fs.appendFileSync(filePath, JSON.stringify(item) + '\n');
299
301
  }
300
302
  catch (e) {
301
- console.error(`[GroupMessageStore] 追加写入失败 (${filePath}):`, e);
303
+ utils_1.logger.error(`[GroupMessageStore] 追加写入失败 (${filePath}):`, e);
302
304
  }
303
305
  }
304
- async writeJsonl(filePath, items) {
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
- await this.ensureDir(path.dirname(filePath));
311
+ this.ensureDir(path.dirname(filePath));
310
312
  try {
311
313
  const lines = items.map(i => JSON.stringify(i)).join('\n');
312
- const content = lines ? lines + '\n' : '';
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
- console.error(`[GroupMessageStore] 全量写入失败 (${filePath}):`, e);
317
+ utils_1.logger.error(`[GroupMessageStore] 全量写入失败 (${filePath}):`, e);
319
318
  }
320
319
  }
321
- async flushMessages(groupId) {
320
+ flushMessages(groupId) {
322
321
  const data = this.groups.get(groupId);
323
322
  if (!data || !this.ownerAid)
324
323
  return;
325
- await this.writeJsonl(this.getMessagesPath(this.ownerAid, groupId), data.messages);
324
+ this.writeJsonl(this.getMessagesPath(this.ownerAid, groupId), data.messages);
326
325
  }
327
- async flushEvents(groupId) {
326
+ flushEvents(groupId) {
328
327
  const data = this.groups.get(groupId);
329
328
  if (!data || !this.ownerAid)
330
329
  return;
331
- await this.writeJsonl(this.getEventsPath(this.ownerAid, groupId), data.events);
330
+ this.writeJsonl(this.getEventsPath(this.ownerAid, groupId), data.events);
332
331
  }
333
- flushIndexQueued() {
334
- var _a;
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
- await this.ensureDir(dir);
342
+ this.ensureDir(dir);
348
343
  const records = Array.from(this.groups.values())
349
344
  .map(d => d.record);
350
345
  try {
351
- const indexPath = this.getIndexPath(this.ownerAid);
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
- console.error('[GroupMessageStore] 写入索引失败:', e);
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
- await this.flushMessages(groupId);
368
- await this.flushEvents(groupId);
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 审核模式返回 request_id,免审核模式返回空字符串
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<string>;
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<string>;
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
  }
@@ -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 审核模式返回 request_id,免审核模式返回空字符串
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.request_id) !== null && _a !== void 0 ? _a : "";
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;
@@ -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[];
@@ -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";