@agentunion/fastaun-browser 0.5.18 → 0.5.20

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.
Files changed (149) hide show
  1. package/CHANGELOG.md +172 -79
  2. package/_packed_docs/CHANGELOG.md +172 -79
  3. package/_packed_docs/INDEX.md +244 -116
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +98 -69
  5. package/_packed_docs/agent.md/SCHEMA.md +245 -205
  6. package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +11 -11
  7. package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +42 -15
  8. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +4 -4
  9. package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +45 -134
  10. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1072 -1072
  11. package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +5 -20
  12. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +687 -668
  13. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +19 -28
  14. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +443 -0
  15. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
  16. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +658 -0
  17. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
  18. package/_packed_docs/protocol/agent.md/SCHEMA.md +4 -0
  19. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +1 -1
  20. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +68 -61
  21. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +1 -1
  22. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +279 -285
  23. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +3 -3
  24. package/_packed_docs/sdk/09-group-rpc-manual.md +271 -235
  25. package/_packed_docs/sdk/09-message-rpc-manual.md +47 -6
  26. package/_packed_docs/sdk/09-storage-rpc-manual.md +70 -68
  27. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +63 -34
  28. package/_packed_docs/sdk/INDEX.md +105 -34
  29. package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
  30. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
  31. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +922 -0
  32. package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
  33. package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +300 -0
  34. package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +382 -0
  35. package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +708 -0
  36. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +476 -0
  37. package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
  38. package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
  39. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +173 -0
  40. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +211 -0
  41. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/345/256/236/347/216/260/347/247/273/346/244/215/346/214/207/345/215/227.md +331 -0
  42. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +207 -0
  43. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/344/273/243/347/240/201/345/256/241/346/237/245/346/212/245/345/221/212.md +252 -0
  44. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/345/256/236/346/226/275/350/256/241/345/210/222.md +156 -0
  45. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/346/226/271/346/241/210.md +273 -0
  46. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/350/257/246/347/273/206/350/256/276/350/256/241.md +211 -0
  47. package/dist/agent-md-schema.d.ts +17 -3
  48. package/dist/agent-md-schema.d.ts.map +1 -1
  49. package/dist/agent-md-schema.js +94 -26
  50. package/dist/agent-md-schema.js.map +1 -1
  51. package/dist/agent-md.d.ts +54 -3
  52. package/dist/agent-md.d.ts.map +1 -1
  53. package/dist/agent-md.js +711 -65
  54. package/dist/agent-md.js.map +1 -1
  55. package/dist/aid-store.d.ts +58 -46
  56. package/dist/aid-store.d.ts.map +1 -1
  57. package/dist/aid-store.js +254 -248
  58. package/dist/aid-store.js.map +1 -1
  59. package/dist/aid.d.ts +4 -1
  60. package/dist/aid.d.ts.map +1 -1
  61. package/dist/aid.js +27 -33
  62. package/dist/aid.js.map +1 -1
  63. package/dist/auth.d.ts +4 -1
  64. package/dist/auth.d.ts.map +1 -1
  65. package/dist/auth.js +426 -39
  66. package/dist/auth.js.map +1 -1
  67. package/dist/bundle.js +38179 -32054
  68. package/dist/cert-utils.d.ts +50 -2
  69. package/dist/cert-utils.d.ts.map +1 -1
  70. package/dist/cert-utils.js +105 -47
  71. package/dist/cert-utils.js.map +1 -1
  72. package/dist/client/delivery.d.ts +22 -1
  73. package/dist/client/delivery.d.ts.map +1 -1
  74. package/dist/client/delivery.js +389 -78
  75. package/dist/client/delivery.js.map +1 -1
  76. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  77. package/dist/client/rpc-pipeline.js +103 -77
  78. package/dist/client/rpc-pipeline.js.map +1 -1
  79. package/dist/client/v2-e2ee.d.ts +1 -0
  80. package/dist/client/v2-e2ee.d.ts.map +1 -1
  81. package/dist/client/v2-e2ee.js +182 -89
  82. package/dist/client/v2-e2ee.js.map +1 -1
  83. package/dist/client.d.ts +100 -1
  84. package/dist/client.d.ts.map +1 -1
  85. package/dist/client.js +1220 -25
  86. package/dist/client.js.map +1 -1
  87. package/dist/crypto.d.ts.map +1 -1
  88. package/dist/crypto.js +8 -6
  89. package/dist/crypto.js.map +1 -1
  90. package/dist/errors.d.ts.map +1 -1
  91. package/dist/errors.js +3 -2
  92. package/dist/errors.js.map +1 -1
  93. package/dist/events.d.ts +9 -2
  94. package/dist/events.d.ts.map +1 -1
  95. package/dist/events.js +72 -13
  96. package/dist/events.js.map +1 -1
  97. package/dist/facades.d.ts +82 -2
  98. package/dist/facades.d.ts.map +1 -1
  99. package/dist/facades.js +100 -6
  100. package/dist/facades.js.map +1 -1
  101. package/dist/index.d.ts +7 -3
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +3 -2
  104. package/dist/index.js.map +1 -1
  105. package/dist/keystore/index.d.ts +17 -0
  106. package/dist/keystore/index.d.ts.map +1 -1
  107. package/dist/keystore/indexeddb-shared.d.ts +10 -1
  108. package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
  109. package/dist/keystore/indexeddb-shared.js +111 -0
  110. package/dist/keystore/indexeddb-shared.js.map +1 -1
  111. package/dist/keystore/indexeddb-token-store.d.ts +7 -1
  112. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
  113. package/dist/keystore/indexeddb-token-store.js +30 -1
  114. package/dist/keystore/indexeddb-token-store.js.map +1 -1
  115. package/dist/org-protocol.d.ts +98 -0
  116. package/dist/org-protocol.d.ts.map +1 -0
  117. package/dist/org-protocol.js +1802 -0
  118. package/dist/org-protocol.js.map +1 -0
  119. package/dist/ownership-proof.d.ts +93 -5
  120. package/dist/ownership-proof.d.ts.map +1 -1
  121. package/dist/ownership-proof.js +239 -53
  122. package/dist/ownership-proof.js.map +1 -1
  123. package/dist/ownership-v21.d.ts +194 -0
  124. package/dist/ownership-v21.d.ts.map +1 -0
  125. package/dist/ownership-v21.js +678 -0
  126. package/dist/ownership-v21.js.map +1 -0
  127. package/dist/ownership-workflow.d.ts +151 -0
  128. package/dist/ownership-workflow.d.ts.map +1 -0
  129. package/dist/ownership-workflow.js +1229 -0
  130. package/dist/ownership-workflow.js.map +1 -0
  131. package/dist/seq-tracker.d.ts +1 -0
  132. package/dist/seq-tracker.d.ts.map +1 -1
  133. package/dist/seq-tracker.js +10 -2
  134. package/dist/seq-tracker.js.map +1 -1
  135. package/dist/tools/cross-sdk-agent.d.ts +83 -0
  136. package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
  137. package/dist/tools/cross-sdk-agent.js +415 -7
  138. package/dist/tools/cross-sdk-agent.js.map +1 -1
  139. package/dist/transport.d.ts +7 -0
  140. package/dist/transport.d.ts.map +1 -1
  141. package/dist/transport.js +90 -2
  142. package/dist/transport.js.map +1 -1
  143. package/dist/v2/e2ee/decrypt.d.ts +1 -0
  144. package/dist/v2/e2ee/decrypt.d.ts.map +1 -1
  145. package/dist/v2/e2ee/decrypt.js +9 -1
  146. package/dist/v2/e2ee/decrypt.js.map +1 -1
  147. package/dist/version.d.ts +1 -1
  148. package/dist/version.js +1 -1
  149. package/package.json +1 -1
@@ -29,28 +29,28 @@
29
29
 
30
30
  | 方法 | 说明 |
31
31
  |------|------|
32
- | [group.add_member](#groupadd_member) | 添加成员 |
33
- | [group.invite_member](#groupinvite_member) | 创建定向邀请 |
34
- | [group.list_my_invites](#grouplist_my_invites) | 列出我的定向邀请 |
35
- | [group.accept_invite](#groupaccept_invite) | 接受定向邀请 |
36
- | [group.reject_invite](#groupreject_invite) | 拒绝定向邀请 |
37
- | [group.revoke_invite](#grouprevoke_invite) | 撤回定向邀请 |
32
+ | [group.add_member](#groupadd_member) | 添加成员 |
33
+ | [group.invite_member](#groupinvite_member) | 创建定向邀请 |
34
+ | [group.list_my_invites](#grouplist_my_invites) | 列出我的定向邀请 |
35
+ | [group.accept_invite](#groupaccept_invite) | 接受定向邀请 |
36
+ | [group.reject_invite](#groupreject_invite) | 拒绝定向邀请 |
37
+ | [group.revoke_invite](#grouprevoke_invite) | 撤回定向邀请 |
38
38
  | [group.get_members](#groupget_members) | 获取成员列表 |
39
39
  | [group.kick](#groupkick) | 踢出成员 |
40
40
  | [group.leave](#groupleave) | 主动退群 |
41
- | [group.set_role](#groupset_role) | 设置角色 |
42
- | [group.transfer_owner](#grouptransfer_owner) | 转让群主 |
43
- | [group.complete_transfer](#groupcomplete_transfer) | 完成群主转让与群身份换钥 |
44
- | [group.bind_group_aid](#groupbind_group_aid) | 为匿名群绑定群身份 |
41
+ | [group.set_role](#groupset_role) | 设置角色 |
42
+ | [group.transfer_owner](#grouptransfer_owner) | 转让群主 |
43
+ | [group.complete_transfer](#groupcomplete_transfer) | 完成群主转让与群身份换钥 |
44
+ | [group.bind_group_aid](#groupbind_group_aid) | 为匿名群绑定群身份 |
45
45
  | [group.renew_group_aid](#grouprenew_group_aid) | 轮换群身份密钥 |
46
- | [group.ban](#groupban) | 封禁成员 |
47
- | [group.unban](#groupunban) | 解封成员 |
48
- | [group.get_banlist](#groupget_banlist) | 获取封禁列表 |
49
- | [group.block](#groupblock) | 屏蔽成员接收群消息 |
50
- | [group.unblock](#groupunblock) | 取消屏蔽 |
51
- | [group.get_blocklist](#groupget_blocklist) | 获取屏蔽列表 |
52
- | [group.report_status](#groupreport_status) | 上报自己的群内状态 |
53
- | [group.get_member_statuses](#groupget_member_statuses) | 获取群成员状态列表 |
46
+ | [group.ban](#groupban) | 封禁成员 |
47
+ | [group.unban](#groupunban) | 解封成员 |
48
+ | [group.get_banlist](#groupget_banlist) | 获取封禁列表 |
49
+ | [group.block](#groupblock) | 屏蔽成员接收群消息 |
50
+ | [group.unblock](#groupunblock) | 取消屏蔽 |
51
+ | [group.get_blocklist](#groupget_blocklist) | 获取屏蔽列表 |
52
+ | [group.report_status](#groupreport_status) | 上报自己的群内状态 |
53
+ | [group.get_member_statuses](#groupget_member_statuses) | 获取群成员状态列表 |
54
54
 
55
55
  ### 入群流程
56
56
 
@@ -83,9 +83,11 @@
83
83
  | [group.pull](#grouppull) | 增量拉取消息 |
84
84
  | [group.history](#grouphistory) | 向前只读翻页群消息 |
85
85
  | [group.pull_events](#grouppull_events) | 增量拉取事件 |
86
- | [group.ack](#groupack) | 确认已读(旧接口,等同 ack_messages) |
86
+ | [group.ack](#groupack) | 确认投递消息游标(旧接口,等同 ack_messages) |
87
87
  | [group.ack_messages](#groupack_messages) | 确认消息游标 |
88
88
  | [group.ack_events](#groupack_events) | 确认事件游标 |
89
+ | [group.read](#groupread) | 上报当前设备的群话题业务已读位置 |
90
+ | [group.read_state](#groupread_state) | 查询当前 AID 的跨设备群已读汇总 |
89
91
 
90
92
  ### 多设备管理
91
93
 
@@ -165,11 +167,21 @@ SDK 发起 `group.*` 调用时会把传入的 `group_id` / `groupId` / `group_ai
165
167
 
166
168
  ## 群组生命周期
167
169
 
170
+ 群 owner 由本节生命周期自动建立、转移和解除,不进入 Ownership 2.1 的 `owner.md`、关系版本、owner 锁、P2P 审批或通用 Facade。创建时群公私钥及证书归初始 owner 持有;解散解除有效 owner 授权;专属转移必须 rekey,旧材料失效,新材料归新 owner。Group 服务从不保存群私钥。
171
+
172
+ ### 群 agent.md 的 owner 代签与上传
173
+
174
+ 新 SDK 群名片 aid 为 group_aid、type=group、owner 为当前群主,entity_cert_fingerprint 为当前群证书指纹;必须省略 ownership、ownership_proof、ownership_release。实体私钥主签,当前 owner token 上传,无需群登录,可选 owner 附签,存在时必须全块验证。取消实体额外 V2 授权头;群证书指纹仍绑定 owner/rekey 代际,完整多签与 CAS 见 [协议 §2.5](../protocol/Ownership协议定义2.1.md#25-grouporg-名片的实体主签与-owner-上传)。
175
+
176
+ 管理员的 group.update、group.index 或文件权限不授予现代群名片上传权。NS 新鲜校验当前 owner、生命周期及群当前证书;Group 旧群证书单签、群身份上传始终兼容,仍执行权威检查与文件 CAS,不据此开放 Org。转移完成后新 owner 用新群材料主签并以本人 token 上传;解散后禁止发布。普通 Ownership Facade 对群目标返回 not_applicable。
177
+
178
+ 新 SDK 群名片全部 NS GET/HEAD/PUT 含 fresh 携带 X-AUN-Signature-Format: multi-v1,返回完整多签及对应 ETag;旧客户端按首签投影读取,多块投影不改完整存储,单块保持原文。实体 fresh GET 还必须同时携带 X-AUN-Ownership-Check: 1 和 Cache-Control: no-cache,Check 头才触发 NS 绕 LRU 全块新鲜验证,不进入通用账本;fresh 返回 not_applicable、实体 current/stale、权威 owner/证书指纹;真正 missing 为 404 且带权威头,无 ETag,依赖失败为 503。verified 下载全块验证历史证书和原文,历史验签不能作为当前授权;上传仍校验当前生命周期和证书,实体代际冲突 409、ETag 冲突 412。
179
+
168
180
  ### group.create
169
181
 
170
- 创建群组。调用者自动成为 owner。支持创建命名群(传入 `group_name` + `public_key`)。新建群主标识以 `group_aid` 为准;`group_id` 仅作为兼容字段保留。
171
-
172
- 四种 SDK 的高层建群接口均支持崩溃恢复。命名群在 RPC 前持久化群密钥,并按 `group_name + public_key` 重放已提交结果;匿名群在 RPC 前持久化群密钥和创建上下文,重试会取回同一数字群并继续 `group_aid` 证书绑定与 `agent.md` 上传。群记录、群主成员、成员索引、入群设置、首个 `group.changed` 事件及匿名创建映射由服务端在同一数据库事务提交;证书服务和存储服务不参与该数据库事务,由 SDK pending 状态和服务端幂等重放恢复。
182
+ 创建群组。调用者自动成为 owner,无需额外 Ownership 绑定。支持创建命名群(传入 `group_name` + `public_key`)。owner 本地生成、持有群私钥,服务端只接收公钥;证书导入 owner 本地后按本节 owner 规则发布群名片。新建群主标识以 `group_aid` 为准;`group_id` 仅作为兼容字段保留。
183
+
184
+ 四种 SDK 的高层建群接口均支持崩溃恢复。命名群在 RPC 前持久化群密钥,并按 `group_name + public_key` 重放已提交结果;匿名群在 RPC 前持久化群密钥和创建上下文,重试会取回同一数字群并继续 `group_aid` 证书绑定与 `agent.md` 上传。群记录、群主成员、成员索引、入群设置、首个 `group.changed` 事件及匿名创建映射由服务端在同一数据库事务提交;证书服务和存储服务不参与该数据库事务,由 SDK pending 状态和服务端幂等重放恢复。
173
185
 
174
186
  **参数**:
175
187
 
@@ -183,7 +195,7 @@ SDK 发起 `group.*` 调用时会把传入的 `group_id` / `groupId` / `group_ai
183
195
  | `curve` | string | 否 | 密钥曲线,默认 `"P-256"` |
184
196
  | `visibility` | string | 否 | `"public"` / `"private"`,默认由配置决定 |
185
197
  | `description` | string | 否 | 群组描述 |
186
- | `metadata` | object | 否 | 自定义元数据 |
198
+ | `metadata` | object | 否 | 自定义元数据;创建时剥离服务托管的 pending_owner_transfer/transfer_history |
187
199
  | `avatar_ref` | string | 否 | 头像存储引用 |
188
200
  | `join_mode` | string | 否 | `"open"` / `"approval"` / `"invite_only"` / `"closed"`,回退到 visibility 映射 |
189
201
  | `join_question` | string | 否 | 入群问题 |
@@ -227,7 +239,7 @@ SDK 发起 `group.*` 调用时会把传入的 `group_id` / `groupId` / `group_ai
227
239
 
228
240
  ### group.bind_aid
229
241
 
230
- 为已有普通群绑定命名 AID(升级为命名群)。仅群主可操作。
242
+ 为已有普通群绑定命名 AID(升级为命名群)。仅群主可操作。这是群身份生命周期操作,不建立 Ownership 2.1 关系;绑定后身份材料由当前 owner 持有。
231
243
 
232
244
  **参数**:
233
245
 
@@ -290,7 +302,7 @@ SDK 发起 `group.*` 调用时会把传入的 `group_id` / `groupId` / `group_ai
290
302
  | `name` | string | 否 | 新名称 |
291
303
  | `visibility` | string | 否 | 新可见性 |
292
304
  | `description` | string | 否 | 新描述 |
293
- | `metadata` | object | 否 | 新元数据 |
305
+ | `metadata` | object | 否 | 新元数据;不得注入、删除或替换服务托管的 pending_owner_transfer/transfer_history |
294
306
  | `avatar_ref` | string | 否 | 新头像存储引用 |
295
307
 
296
308
  ### group.list_my
@@ -355,7 +367,7 @@ SDK 发起 `group.*` 调用时会把传入的 `group_id` / `groupId` / `group_ai
355
367
 
356
368
  ### group.suspend
357
369
 
358
- 暂停群组。暂停期间 owner/admin 可以继续通过 `group.send`、`group.v2.send` 和 `group.thought.put` 发言;member 禁止发言,入群、邀请、申请审批等准入操作继续拒绝。需要 **admin 及以上**权限。
370
+ 暂停群组。暂停期间 owner/admin 可以继续通过 `group.send`、`group.v2.send` 和 `group.thought.put` 发言;member 禁止发言,入群、邀请、申请审批等准入操作继续拒绝。需要 **admin 及以上**权限。
359
371
 
360
372
  **参数**:`group_id`(string,必填;兼容字段,值使用目标态 `group_aid`)
361
373
 
@@ -389,7 +401,7 @@ SDK 发起 `group.*` 调用时会把传入的 `group_id` / `groupId` / `group_ai
389
401
 
390
402
  ### group.dissolve
391
403
 
392
- 永久解散群组。不可恢复。需要 **owner** 权限。
404
+ 永久解散群组。不可恢复。需要 **owner** 权限。解散自动解除有效 owner 关系、终止待转移,并撤销群证书及群授权;旧实体材料、群 token 和 pending 不能继续鉴权或上传群名片。历史 owner 与原始签名仅用于审计。服务先原子提交解散墓碑并清除转移待办,再通过持久 outbox 完成事件发布、CA 撤销、Storage 权限失效及缓存清理;任一收尾未完成,RPC 返回 -32002,data 为 status=unavailable、retryable=true、committed=true。墓碑已生效,重试续跑原收尾,不提前返回成功。
393
405
 
394
406
  **参数**:`group_id`(string,必填;兼容字段,值使用目标态 `group_aid`)
395
407
 
@@ -409,7 +421,7 @@ SDK 发起 `group.*` 调用时会把传入的 `group_id` / `groupId` / `group_ai
409
421
 
410
422
  ### group.add_member
411
423
 
412
- 添加成员。需要 **owner** 权限;普通指定 AID 入群应使用 `group.invite_member`。若设置 `role=admin`,仍需 owner 权限。
424
+ 添加成员。需要 **owner** 权限;普通指定 AID 入群应使用 `group.invite_member`。若设置 `role=admin`,仍需 owner 权限。
413
425
 
414
426
  **参数**:
415
427
 
@@ -538,76 +550,76 @@ SDK 发起 `group.*` 调用时会把传入的 `group_id` / `groupId` / `group_ai
538
550
  }
539
551
  ```
540
552
 
541
- ### group.transfer_owner
542
-
543
- 发起两阶段群主转让。需要 owner 权限;该调用只记录待换钥状态,不会立即变更群主。新群主完成 `group.complete_transfer` 后,原 owner 才转为 admin。
553
+ ### group.transfer_owner
554
+
555
+ 发起两阶段群主转让。需要 owner 权限;该调用只记录待换钥状态,不会立即变更群主。新群主完成 `group.complete_transfer` 后,原 owner 才转为 admin。
544
556
 
545
557
  **参数**:
546
558
 
547
559
  | 参数 | 类型 | 必填 | 说明 |
548
- |------|------|------|------|
549
- | `group_id` | string | 是 | 群组标识;兼容字段,值语义为目标态 `group_aid` |
550
- | `group_aid` | string | 否 | 群身份;高层 SDK 会查询并补齐 |
551
- | `new_owner` | string | 是 | 新群主 AID(也接受 `aid`) |
552
- | `transfer_auth` | object | 是 | 旧群主使用当前 group_aid 私钥签名的授权,包含 `nonce`、`issued_ms`、`signature` |
560
+ |------|------|------|------|
561
+ | `group_id` | string | 是 | 群组标识;兼容字段,值语义为目标态 `group_aid` |
562
+ | `group_aid` | string | 否 | 群身份;高层 SDK 会查询并补齐 |
563
+ | `new_owner` | string | 是 | 新群主 AID(也接受 `aid`) |
564
+ | `transfer_auth` | object | 是 | 旧群主使用当前 group_aid 私钥签名的授权,包含 `nonce`、`issued_ms`、`signature` |
553
565
 
554
566
  **响应**:
555
567
 
556
568
  ```json
557
- {
558
- "status": "pending_rekey",
559
- "requires_ca_rekey": true,
560
- "complete_rpc": "group.complete_transfer",
561
- "group": { ... },
562
- "group_id": "team.agentid.pub",
563
- "group_aid": "team.agentid.pub",
564
- "old_owner": "alice.agentid.pub",
565
- "new_owner": "bob.agentid.pub",
566
- "pending_owner_transfer": {
567
- "status": "pending_rekey",
568
- "old_owner": "alice.agentid.pub",
569
- "new_owner": "bob.agentid.pub",
570
- "group_aid": "team.agentid.pub",
571
- "transfer_auth": { ... }
572
- }
573
- }
574
- ```
575
-
576
- 四语言 SDK 会在新群主在线收到 `owner_transfer_rekey_pending` 事件,或重连发现本地 pending 状态时自动尝试完成转让。发起方的高层转让方法返回上述 `pending_rekey`,不会等待新群主完成。Python / TypeScript / JavaScript 门面需要传入 `aid_store` / `aidStore` 才执行签名编排;Go 的高层发起入口为 `AUNClient.StartGroupTransfer`,`GroupFacade.TransferOwner` 当前是原始 RPC 门面。
577
-
578
- ### group.complete_transfer
579
-
580
- 由 pending 中的新群主完成群身份换钥和所有权切换。成功后响应状态为 `transferred`,新群主成为 owner,原群主转为 admin。
581
-
582
- **参数**:
583
-
584
- | 参数 | 类型 | 必填 | 说明 |
585
- |------|------|------|------|
586
- | `group_id` | string | 是 | 群组标识;兼容字段,值语义为目标态 `group_aid` |
587
- | `group_aid` | string | 否 | 群身份;高层 SDK 会查询并补齐 |
588
- | `public_key` | string | 是 | 新 group_aid 公钥 DER base64(SPKI 格式) |
589
- | `curve` | string | 否 | 曲线名称,默认 `P-256` |
590
- | `transfer_accept` | object | 是 | 新群主使用自身 AID 私钥签名的接受证明,包含 `nonce`、`issued_ms`、`signature` |
591
-
592
- **响应**:
593
-
594
- ```json
595
- {
596
- "status": "transferred",
597
- "group": { ... },
598
- "group_id": "team.agentid.pub",
599
- "group_aid": "team.agentid.pub",
600
- "old_owner": "alice.agentid.pub",
601
- "new_owner": "bob.agentid.pub",
602
- "aid_cert": { "cert": "-----BEGIN CERTIFICATE-----..." }
603
- }
604
- ```
605
-
606
- 高层 SDK 会生成并暂存新群身份密钥,签名 `transfer_accept`,成功后导入新的 group_aid 身份;重复提交同一已完成转让时,服务端可幂等返回已完成结果。
569
+ {
570
+ "status": "pending_rekey",
571
+ "requires_ca_rekey": true,
572
+ "complete_rpc": "group.complete_transfer",
573
+ "group": { ... },
574
+ "group_id": "team.agentid.pub",
575
+ "group_aid": "team.agentid.pub",
576
+ "old_owner": "alice.agentid.pub",
577
+ "new_owner": "bob.agentid.pub",
578
+ "pending_owner_transfer": {
579
+ "status": "pending_rekey",
580
+ "old_owner": "alice.agentid.pub",
581
+ "new_owner": "bob.agentid.pub",
582
+ "group_aid": "team.agentid.pub",
583
+ "transfer_auth": { ... }
584
+ }
585
+ }
586
+ ```
587
+
588
+ 四语言 SDK 会在新群主在线收到 `owner_transfer_rekey_pending` 事件,或重连发现本地 pending 状态时自动尝试完成转让。发起方的高层转让方法返回上述 `pending_rekey`,不会等待新群主完成。Python / TypeScript / JavaScript 门面需要传入 `aid_store` / `aidStore` 才执行签名编排;Go 的高层发起入口为 `AUNClient.StartGroupTransfer`,`GroupFacade.TransferOwner` 当前是原始 RPC 门面。
589
+
590
+ ### group.complete_transfer
591
+
592
+ 由 pending 中的新群主完成群身份换钥和所有权切换,必须使用新密钥,禁止同密钥续证代替 rekey。成功后响应状态为 `transferred`,新群主成为 owner,原群主转为 admin;旧群证书失效,新群私钥及证书由新 owner 本地持有。
593
+
594
+ **参数**:
595
+
596
+ | 参数 | 类型 | 必填 | 说明 |
597
+ |------|------|------|------|
598
+ | `group_id` | string | 是 | 群组标识;兼容字段,值语义为目标态 `group_aid` |
599
+ | `group_aid` | string | 否 | 群身份;高层 SDK 会查询并补齐 |
600
+ | `public_key` | string | 是 | 新 group_aid 公钥 DER base64(SPKI 格式) |
601
+ | `curve` | string | 否 | 曲线名称,默认 `P-256` |
602
+ | `transfer_accept` | object | 是 | 新群主使用自身 AID 私钥签名的接受证明,包含 `nonce`、`issued_ms`、`signature` |
603
+
604
+ **响应**:
605
+
606
+ ```json
607
+ {
608
+ "status": "transferred",
609
+ "group": { ... },
610
+ "group_id": "team.agentid.pub",
611
+ "group_aid": "team.agentid.pub",
612
+ "old_owner": "alice.agentid.pub",
613
+ "new_owner": "bob.agentid.pub",
614
+ "aid_cert": { "cert": "-----BEGIN CERTIFICATE-----..." }
615
+ }
616
+ ```
617
+
618
+ 高层 SDK 会生成并暂存新群身份密钥,签名 `transfer_accept`,成功后导入新的 group_aid 身份,并用新群私钥主签、由新 owner token 上传含新 owner 的群名片,可选 owner 附签;名片失败保留新代际原字节和原 CAS 条件,不反向撤销 owner 切换。重复提交同一已完成转让时,服务端可幂等返回已完成结果;旧 owner 的 pending 不得改用新代际自动续传。服务持久保留已验证旧证书用于 CA 轮换后复核原授权,以 transfer nonce 和旧 serial CAS 防止旧请求提交新任务;CA 已提交且可恢复的原待办即使超过 TTL 仍可收敛,尚未提交 CA 的过期待办拒绝。
607
619
 
608
620
  ### group.bind_group_aid
609
621
 
610
- 为匿名群绑定群身份(group_aid)。需要 owner 权限。
622
+ 为匿名群绑定群身份(group_aid)。需要 owner 权限。这不是 Ownership 绑定;成功后当前 owner 持有群身份材料,并以本人身份代签代上传群名片。
611
623
 
612
624
  **幂等保证**:
613
625
  - 已绑定且公钥匹配:返回已绑定的 group_aid 和证书
@@ -647,7 +659,7 @@ SDK 发起 `group.*` 调用时会把传入的 `group_id` / `groupId` / `group_ai
647
659
 
648
660
  ### group.renew_group_aid
649
661
 
650
- 轮换群身份密钥。需要 owner 权限,且必须持有旧 group_aid 私钥。
662
+ 轮换群身份密钥。需要 owner 权限,且必须持有旧 group_aid 私钥。这是当前 owner 的主动换钥,不替代 `transfer_owner/complete_transfer`。成功后旧群证书失效,owner 持有新材料并以本人身份重新代签代上传群名片。
651
663
 
652
664
  **用途**:
653
665
  - 群主密钥泄露后的安全轮换
@@ -758,7 +770,7 @@ aun-group-aid-renew-v1|{group_id}|{group_aid}|{sha256(old_public_key)}|{sha256(n
758
770
  }
759
771
  ```
760
772
 
761
- ### group.get_banlist
773
+ ### group.get_banlist
762
774
 
763
775
  获取封禁列表。需要 **admin 及以上**权限。
764
776
 
@@ -782,88 +794,88 @@ aun-group-aid-renew-v1|{group_id}|{group_aid}|{sha256(old_public_key)}|{sha256(n
782
794
  "total": 1,
783
795
  "page": 1,
784
796
  "size": 200
785
- }
786
- ```
787
-
788
- 禁言与屏蔽是两个独立状态,可以同时设置。禁言成员仍能接收群消息,但不能发送;屏蔽成员仍能发送群消息,但不再收到该群的实时消息 Push、离线消息 Push、Pull 或 E2EE wrap。
789
-
790
- ### group.block
791
-
792
- 屏蔽成员接收群消息。owner/admin 可以屏蔽其权限范围内的成员;所有成员都可以屏蔽自己。屏蔽只影响接收,不影响该成员向群内发送消息,也不改变已有禁言状态。
793
-
794
- **参数**:`group_id`(string,必填;兼容字段,值使用目标态 `group_aid`),`subject` 或 `aid`(string,必填;传入自己的 AID 即可屏蔽自己),`reason`(string,可选)。
795
-
796
- **响应**:
797
-
798
- ```json
799
- {
800
- "group_id": "g-abc123.agentid.pub",
801
- "group_aid": "g-abc123.agentid.pub",
802
- "block": {
803
- "group_id": "g-abc123.agentid.pub",
804
- "subject": "bob.agentid.pub",
805
- "blocked_by": "alice.agentid.pub",
806
- "reason": "暂不接收群消息",
807
- "created_at": 1234567890000
808
- }
809
- }
810
- ```
811
-
812
- ### group.unblock
813
-
814
- 取消屏蔽。owner/admin 可以取消其权限范围内成员的屏蔽;所有成员都可以取消自己的屏蔽。取消屏蔽不改变禁言状态。
815
-
816
- **参数**:`group_id`(string,必填),`subject` 或 `aid`(string,必填;传入自己的 AID 即可取消自己的屏蔽)。
817
-
818
- **响应**:`{ "group_id": "g-abc123.agentid.pub", "group_aid": "g-abc123.agentid.pub", "subject": "bob.agentid.pub", "status": "removed" }`
819
-
820
- ### group.get_blocklist
821
-
822
- 获取群屏蔽列表。需要 **admin 及以上**权限。
823
-
824
- **参数**:`group_id`(string,必填)
825
-
826
- **响应**:`{ "group_id": "g-abc123.agentid.pub", "group_aid": "g-abc123.agentid.pub", "items": [ ... ], "total": 1, "page": 1, "size": 1 }`
827
-
828
- 每个条目包含 `group_id`、`subject`、`blocked_by`、`reason` 和 `created_at`。
829
-
830
- ### group.report_status
831
-
832
- 上报当前成员在指定群内的在线状态和工作状态。调用者只能上报自己的状态;`updated_at` 由服务端记录。消息发送成功后,服务端独立维护该成员的 `last_message_at` 和 `last_payload_type`。
833
-
834
- **参数**:`group_id`(string,必填),`online_status`(string,必填),`work_status`(string,必填)。
835
-
836
- **响应**:`{ "group_id": "g-abc123.agentid.pub", "group_aid": "g-abc123.agentid.pub", "status": { ... } }`
837
-
838
- ### group.get_member_statuses
839
-
840
- 查询群内所有成员状态。调用者必须是群成员。响应始终以数组返回,并包含尚未上报状态的成员。
841
-
842
- **参数**:`group_id`(string,必填)
843
-
844
- **响应**:
845
-
846
- ```json
847
- {
848
- "group_id": "g-abc123.agentid.pub",
849
- "group_aid": "g-abc123.agentid.pub",
850
- "items": [
851
- {
852
- "group_id": "g-abc123.agentid.pub",
853
- "aid": "alice.agentid.pub",
854
- "online_status": "online",
855
- "work_status": "busy",
856
- "updated_at": 1234567890000,
857
- "last_message_at": 1234567890123,
858
- "last_payload_type": "text"
859
- }
860
- ]
861
- }
862
- ```
863
-
864
- `online_status` 和 `work_status` 是成员上报值;未上报时为空字符串。`last_message_at` 为该成员在此群最后一条成功发送消息的时间,`last_payload_type` 为该消息的 `payload.type`;没有历史消息时分别为 `0` 和空字符串。
865
-
866
- ---
797
+ }
798
+ ```
799
+
800
+ 禁言与屏蔽是两个独立状态,可以同时设置。禁言成员仍能接收群消息,但不能发送;屏蔽成员仍能发送群消息,但不再收到该群的实时消息 Push、离线消息 Push、Pull 或 E2EE wrap。
801
+
802
+ ### group.block
803
+
804
+ 屏蔽成员接收群消息。owner/admin 可以屏蔽其权限范围内的成员;所有成员都可以屏蔽自己。屏蔽只影响接收,不影响该成员向群内发送消息,也不改变已有禁言状态。
805
+
806
+ **参数**:`group_id`(string,必填;兼容字段,值使用目标态 `group_aid`),`subject` 或 `aid`(string,必填;传入自己的 AID 即可屏蔽自己),`reason`(string,可选)。
807
+
808
+ **响应**:
809
+
810
+ ```json
811
+ {
812
+ "group_id": "g-abc123.agentid.pub",
813
+ "group_aid": "g-abc123.agentid.pub",
814
+ "block": {
815
+ "group_id": "g-abc123.agentid.pub",
816
+ "subject": "bob.agentid.pub",
817
+ "blocked_by": "alice.agentid.pub",
818
+ "reason": "暂不接收群消息",
819
+ "created_at": 1234567890000
820
+ }
821
+ }
822
+ ```
823
+
824
+ ### group.unblock
825
+
826
+ 取消屏蔽。owner/admin 可以取消其权限范围内成员的屏蔽;所有成员都可以取消自己的屏蔽。取消屏蔽不改变禁言状态。
827
+
828
+ **参数**:`group_id`(string,必填),`subject` 或 `aid`(string,必填;传入自己的 AID 即可取消自己的屏蔽)。
829
+
830
+ **响应**:`{ "group_id": "g-abc123.agentid.pub", "group_aid": "g-abc123.agentid.pub", "subject": "bob.agentid.pub", "status": "removed" }`
831
+
832
+ ### group.get_blocklist
833
+
834
+ 获取群屏蔽列表。需要 **admin 及以上**权限。
835
+
836
+ **参数**:`group_id`(string,必填)
837
+
838
+ **响应**:`{ "group_id": "g-abc123.agentid.pub", "group_aid": "g-abc123.agentid.pub", "items": [ ... ], "total": 1, "page": 1, "size": 1 }`
839
+
840
+ 每个条目包含 `group_id`、`subject`、`blocked_by`、`reason` 和 `created_at`。
841
+
842
+ ### group.report_status
843
+
844
+ 上报当前成员在指定群内的在线状态和工作状态。调用者只能上报自己的状态;`updated_at` 由服务端记录。消息发送成功后,服务端独立维护该成员的 `last_message_at` 和 `last_payload_type`。
845
+
846
+ **参数**:`group_id`(string,必填),`online_status`(string,必填),`work_status`(string,必填)。
847
+
848
+ **响应**:`{ "group_id": "g-abc123.agentid.pub", "group_aid": "g-abc123.agentid.pub", "status": { ... } }`
849
+
850
+ ### group.get_member_statuses
851
+
852
+ 查询群内所有成员状态。调用者必须是群成员。响应始终以数组返回,并包含尚未上报状态的成员。
853
+
854
+ **参数**:`group_id`(string,必填)
855
+
856
+ **响应**:
857
+
858
+ ```json
859
+ {
860
+ "group_id": "g-abc123.agentid.pub",
861
+ "group_aid": "g-abc123.agentid.pub",
862
+ "items": [
863
+ {
864
+ "group_id": "g-abc123.agentid.pub",
865
+ "aid": "alice.agentid.pub",
866
+ "online_status": "online",
867
+ "work_status": "busy",
868
+ "updated_at": 1234567890000,
869
+ "last_message_at": 1234567890123,
870
+ "last_payload_type": "text"
871
+ }
872
+ ]
873
+ }
874
+ ```
875
+
876
+ `online_status` 和 `work_status` 是成员上报值;未上报时为空字符串。`last_message_at` 为该成员在此群最后一条成功发送消息的时间,`last_payload_type` 为该消息的 `payload.type`;没有历史消息时分别为 `0` 和空字符串。
877
+
878
+ ---
867
879
 
868
880
  ## 入群流程
869
881
 
@@ -1245,7 +1257,7 @@ SDK 观察到 `_meta.group_indexes` 只记录远端 etag,不会自动覆盖本
1245
1257
 
1246
1258
  ### group.send
1247
1259
 
1248
- 发送群消息。需要 member 权限。群为 `suspended` 时仅 owner/admin 可以发送,member 会被拒绝。
1260
+ 发送群消息。需要 member 权限。群为 `suspended` 时仅 owner/admin 可以发送,member 会被拒绝。
1249
1261
 
1250
1262
  群消息的持久化 `mention_mode` 来自群设置,取值为 `"disabled"` / `"mention-only"`;服务端会写入消息对象并在 pull / push 中返回。运行时是否广播全员或分发给值班 Agent,由响应中的 `dispatch` / `message_dispatch` 描述。V2 加密消息把快照放在既有 `envelope_json` 元数据中,不改变 `per_device` 投递列。
1251
1263
 
@@ -1311,7 +1323,7 @@ SDK 观察到 `_meta.group_indexes` 只记录远端 etag,不会自动覆盖本
1311
1323
 
1312
1324
  ### group.thought.put
1313
1325
 
1314
- 写入某个发送者针对一个群上下文的思考内容。该内容不是普通群消息:服务端不分配消息 `seq`,不广播,不进入 `group.pull`,不需要 ack,也不持久化;只在内存中保留当前 head。群为 `suspended` 时仅 owner/admin 可以写入,member 会被拒绝。
1326
+ 写入某个发送者针对一个群上下文的思考内容。该内容不是普通群消息:服务端不分配消息 `seq`,不广播,不进入 `group.pull`,不需要 ack,也不持久化;只在内存中保留当前 head。群为 `suspended` 时仅 owner/admin 可以写入,member 会被拒绝。
1315
1327
 
1316
1328
  SDK 调用时必须走群组 E2EE。应用层传入明文 `payload`,SDK 会加密成 V2 `e2ee.group_encrypted` 信封、补齐 `thought_id` / `timestamp`,并附加 `client_signature`。裸 WebSocket 客户端若绕过 SDK,至少必须自行完成 V2 envelope、`sender_signature`、AAD 和 state commitment 生成;`client_signature` 按 Gateway 连接级身份语义携带。
1317
1329
 
@@ -1426,7 +1438,7 @@ result = await client.call("group.thought.get", {
1426
1438
  |------|------|------|--------|------|
1427
1439
  | `group_id` | string | 是 | — | 群组标识;兼容字段,值语义为目标态 `group_aid` |
1428
1440
  | `after_message_seq` | integer | 否 | 0 | 从该消息 seq 之后拉取 |
1429
- | `limit` | integer | 否 | 50 | 最大条数(最大 50;`pull_max_limit` 配置只能进一步收紧) |
1441
+ | `limit` | integer | 否 | 50 | SDK 单页上限,最大 50;`pull_max_limit` 配置可进一步收紧 |
1430
1442
  | `device_id` | string | 否 | — | 设备 ID(多设备模式) |
1431
1443
 
1432
1444
  **响应**:
@@ -1445,13 +1457,17 @@ result = await client.call("group.thought.get", {
1445
1457
 
1446
1458
  多设备模式时额外返回 `cursor` 对象(含 `current_seq`、`join_seq`、`latest_seq`、`unread_count`)。
1447
1459
 
1460
+ 旧 `group.pull` 的服务端 `has_more` 通过 `limit + 1` 可见消息探测及响应截页确定,表示仍有当前成员可见的消息未返回,不由 `unread_count` 或恰好满页推断。底层 `group.v2.pull` 的 Forward 响应可不含该字段,SDK 仍结合 head 与游标判断是否续页。
1461
+
1462
+ 当前四个 SDK 的 V2 路由仍将单页限制为 50。直接调用底层 `group.v2.pull` 时,服务端默认 50、最大 200,受 `pull_max_limit` 配置进一步限制;旧 `group.pull`、`group.history` 与 `group.pull_events` 仍为最大 50。
1463
+
1448
1464
  `group.pull` 是公开的 Forward Pull。实时 A/T/H 最新页同步由 SDK 内部自动完成,不提供需要应用传入的模式参数。普通 Forward 中,`retention_floor_message_seq` 只表示已提交物理 GC;`earliest_available_message_seq-1` 表示服务端综合 retention、入群点和 epoch 后的当前成员可见性排他下界。SDK 以 `max(retention_floor_message_seq, cursor.join_seq, earliest_available_message_seq-1)` 推进 A;History 不修改 A/T/H。
1449
1465
 
1450
- Forward 原始页校验通过后按页内最大 seq 推进 A,单条解密失败通过 `group.message_undecryptable` 报告而不阻塞水位。Piggy ACK 保留:有待提交 ACK 时,非满页会继续拉一页并携带 ACK,空页后停止。
1451
-
1452
- `group.pull` 与 `group.history` 进入当前 `AUNClient` 的客户端级 Pull Gate。该 Gate 与 P2P Message、Group Event Pull 共享,始终 single-inflight;相同请求 key 折叠并共享结果,不同 key 按前台 FIFO(Tail/History)优先于后台 FIFO(Forward/Gap Fill/Group Event)排队。不同 `AUNClient` 实例之间不共享 Gate,应用层无需自行实现并发控制。
1453
-
1454
- 解密当前群消息时若缺少 sender IK,SDK 先执行同发送端 single-flight 的有界同步 bootstrap,最多等待 3 秒;P2P bootstrap 未命中时可继续读取 Group bootstrap。成功后立即重试当前消息,失败或超时才 pending,且不阻塞实时扫描水位。
1466
+ Forward 原始页校验通过后按页内最大 seq 推进 A,单条解密失败通过 `group.message_undecryptable` 报告而不阻塞水位。Piggy ACK 保留:有后续页时携带待提交 ACK;没有续页证明时以独立 ACK 收尾,不为 ACK 额外拉取空页。
1467
+
1468
+ `group.pull` 与 `group.history` 进入当前 `AUNClient` 的客户端级 Pull Gate。该 Gate 与 P2P Message、Group Event Pull 共享,同一 namespace 内的 Tail、History、Forward 始终单飞,不同 namespace 最多 4 个并行。namespace 分别为 `p2p:{当前 AID}`、`group:{群标识}`、`group_event:{群标识}`,同群消息与群事件使用不同 namespace。相同完整请求 key 折叠并共享结果;可运行的不同 key 按前台 FIFO(Tail/History)优先于后台 FIFO(Forward/Gap Fill/Group Event)调度,跳过已被占用的 namespace。不同 `AUNClient` 实例之间不共享 Gate,应用层无需自行实现并发控制。
1469
+
1470
+ 解密当前群消息时若缺少 sender IK,SDK 先执行同发送端 single-flight 的有界同步 bootstrap,最多等待 3 秒;P2P bootstrap 未命中时可继续读取 Group bootstrap。成功后立即重试当前消息,失败或超时才 pending,且不阻塞实时扫描水位。
1455
1471
 
1456
1472
  SDK 只保证单个实时拉取响应页内按 seq 升序、同 seq 最多发布一次。A/T/H 是扫描水位,不记录应用是否已经收到回调;跨 Push、SDK 自动最新页同步和 Forward 页允许重复和乱序。全局去重与排序由应用业务仓库负责,不是 SDK 交付契约;应用必须在群 namespace 内按 `message_id` 幂等并按 `seq` 排序。SDK 进程内折叠仅作 best-effort 优化。History 只返回结果,不参与实时发布。
1457
1473
 
@@ -1471,7 +1487,7 @@ SDK 只保证单个实时拉取响应页内按 seq 升序、同 seq 最多发布
1471
1487
 
1472
1488
  ### group.ack
1473
1489
 
1474
- 提交群消息已读游标。等同于 `group.ack_messages`,需要 `device_id`。
1490
+ 提交群消息投递消费游标。等同于 `group.ack_messages`,需要 `device_id`;业务已读独立使用 `group.read/read_state`。
1475
1491
 
1476
1492
  **参数**:
1477
1493
 
@@ -1584,11 +1600,11 @@ SDK 只保证单个实时拉取响应页内按 seq 升序、同 seq 最多发布
1584
1600
 
1585
1601
  查看群文件系统用量。参数可传 `path` 或 `group_id`。
1586
1602
 
1587
- ### group.fs.create_download_ticket
1588
-
1589
- 创建下载票据。参数:`path` 必填。响应包含 `url` / `download_url`、`expire_at`,以及可选的 `token`、`sha256`、`content_type`、`file_name`。私有文件和跨 issuer 文件由资源所在域签发短 TTL 的 `?t=` 能力凭据;Group 只返回票据,不代理文件字节。
1590
-
1591
- SDK Group FS 门面使用票据执行 HTTP GET 并校验 sha256。应用自行下载时遵守与 `storage.create_download_ticket` 相同的数据面规则:完整保留 URL 中的 `?t=`;只有端点明确要求 AID Bearer 时,才在每次请求前调用 Python `get_access_token()`、TypeScript / JavaScript `getAccessToken()` 或 Go `GetAccessToken()`;不得长期复用 `authenticate()` 首次返回的 token,也不得把当前域的 AID JWT 发送给另一 issuer 的 storage。401/403 仅在重新读取到不同 token 时重试一次;票据过期应重新申请。完整流程见 [Storage RPC 手册](09-storage-rpc-manual.md#数据面-http-下载流程)。
1603
+ ### group.fs.create_download_ticket
1604
+
1605
+ 创建下载票据。参数:`path` 必填。响应包含 `url` / `download_url`、`expire_at`,以及可选的 `token`、`sha256`、`content_type`、`file_name`。私有文件和跨 issuer 文件由资源所在域签发短 TTL 的 `?t=` 能力凭据;Group 只返回票据,不代理文件字节。
1606
+
1607
+ SDK Group FS 门面使用票据执行 HTTP GET 并校验 sha256。应用自行下载时遵守与 `storage.create_download_ticket` 相同的数据面规则:完整保留 URL 中的 `?t=`;只有端点明确要求 AID Bearer 时,才在每次请求前调用 Python `get_access_token()`、TypeScript / JavaScript `getAccessToken()` 或 Go `GetAccessToken()`;不得长期复用 `authenticate()` 首次返回的 token,也不得把当前域的 AID JWT 发送给另一 issuer 的 storage。401/403 仅在重新读取到不同 token 时重试一次;票据过期应重新申请。完整流程见 [Storage RPC 手册](09-storage-rpc-manual.md#数据面-http-下载流程)。
1592
1608
 
1593
1609
  ### group.fs.set_acl
1594
1610
 
@@ -1634,7 +1650,7 @@ SDK Group FS 门面使用票据执行 HTTP GET 并校验 sha256。应用自行
1634
1650
 
1635
1651
  ### group.fs.create_upload_session
1636
1652
 
1637
- 创建上传会话。参数同 `check_upload`。响应透传 Storage session 字段并增加 Group FS 路径视图,包含 `upload_url`、`content_type`、`size_bytes` 等;当前 Storage 服务不返回 `session_id` 或 `headers`。四个 SDK 的 Group FS 门面会按实际字节识别 MIME,并在 session、HTTP PUT 与 complete 中保持 `Content-Type` 一致;若 session 返回 headers,SDK 保留其它 header 并替换其中的 Content-Type,避免 OSS 签名不一致导致 403。
1653
+ 创建上传会话。参数同 `check_upload`。响应透传 Storage session 字段并增加 Group FS 路径视图,包含 `upload_url`、`content_type`、`size_bytes` 等;当前 Storage 服务不返回 `session_id` 或 `headers`。四个 SDK 的 Group FS 门面会按实际字节识别 MIME,并在 session、HTTP PUT 与 complete 中保持 `Content-Type` 一致;若 session 返回 headers,SDK 保留其它 header 并替换其中的 Content-Type,避免 OSS 签名不一致导致 403。
1638
1654
 
1639
1655
  ### group.fs.complete_upload
1640
1656
 
@@ -1687,7 +1703,7 @@ SDK Group FS 门面使用票据执行 HTTP GET 并校验 sha256。应用自行
1687
1703
 
1688
1704
  ### group.pull_events
1689
1705
 
1690
- 增量拉取群事件,支持多设备独立游标。SDK 将其作为后台 Pull 放入当前 `AUNClient` 的客户端级 Pull Gate;该 Gate 与 P2P Message、Group Message Pull 共享,始终 single-inflight,相同请求 key 折叠并共享结果,不同 key 按后台 FIFO 排队。Group Event 使用独立的 Forward Cursor,不修改消息 A/T/H;不同 `AUNClient` 实例之间不共享 Gate。应用层无需自行实现并发控制。
1706
+ 增量拉取群事件,支持多设备独立游标。SDK 将其作为后台 Pull 放入当前 `AUNClient` 的客户端级 Pull Gate;该 Gate 与 P2P Message、Group Message Pull 共享,同一 namespace 单飞,客户端最多 4 个不同 namespace 并行。Group Event 使用 `group_event:{群标识}`,与同群消息 namespace 独立;相同完整请求 key 折叠并共享结果,可运行的不同 key 按后台 FIFO 调度并让前台请求优先。Group Event 使用独立的 Forward Cursor,不修改消息 A/T/H;不同 `AUNClient` 实例之间不共享 Gate。应用层无需自行实现并发控制。
1691
1707
 
1692
1708
  **参数**:
1693
1709
 
@@ -1721,7 +1737,7 @@ SDK Group FS 门面使用票据执行 HTTP GET 并校验 sha256。应用自行
1721
1737
  }
1722
1738
  ```
1723
1739
 
1724
- > `retention_floor_event_seq` 只表示已提交物理 GC;`earliest_available_event_seq-1` 是综合 retention、入群点和 epoch 后的当前成员可见性排他下界。SDK 以 `max(retention_floor_event_seq, cursor.current_seq, cursor.join_seq, earliest_available_event_seq-1)` 恢复或推进 Group Event A,ACK 仍只能提交已持久化 A。`cursor` 仅多设备模式(提供 `device_id`)时返回。响应大小受 `pull_max_response_bytes` 配置限制。
1740
+ > `retention_floor_event_seq` 只表示已提交物理 GC;`earliest_available_event_seq-1` 是综合 retention、入群点和 epoch 后的当前成员可见性排他下界。SDK 以 `max(retention_floor_event_seq, cursor.current_seq, cursor.join_seq, earliest_available_event_seq-1)` 恢复或推进 Group Event A,ACK 仍只能提交已持久化 A。`cursor` 仅多设备模式(提供 `device_id`)时返回。响应大小受 `pull_max_response_bytes` 配置限制。`has_more` 通过 `limit + 1` 可见事件探测及响应截页确定,不由 `unread_count` 或恰好满页推断。
1725
1741
 
1726
1742
  ### group.ack_messages
1727
1743
 
@@ -1868,6 +1884,26 @@ SDK Group FS 门面使用票据执行 HTTP GET 并校验 sha256。应用自行
1868
1884
 
1869
1885
  ---
1870
1886
 
1887
+ ## group.read
1888
+
1889
+ 请求为 `{"states":[{"group_id":"team.agentid.pub","topic_key":"topic-1","last_read_message_id":"gm-100"}]}`。`scope` 缺省或为空时按 `group` 处理,非空值只能为 `group`。AID 与 device ID 使用认证连接;历史 Group ID 别名先解析为 canonical ID,新写状态键、响应和事件使用 canonical `group_id`;历史别名同时参与事实、公共位置和设备映射的事务查询。Group 复用现有群成员及封禁检查,通过既有 `RequireSendGroup` 与版本同步刷新跨实例权限。批量至少一项,仅更新出现的键;只有省略 `states` 时才兼容顶层单条,显式空数组、null 或非数组值拒绝;字符串字段显式传入非字符串或 `null` 时拒绝。同域批量先校验该域全部项;混合域按所属域首次出现的顺序逐域校验和提交,任何域失败则 RPC 返回错误,已经提交的域不回滚,通过幂等重试收敛。owner/device/group/topic/message ID 各最多 128 字符,topic 原样保存。
1890
+
1891
+ 响应为 `{"updated":1,"ignored":0,"states":[{"scope":"group","group_id":"team.agentid.pub","topic_key":"topic-1","last_read_message_id":"gm-100","changed":true}]}`。这是设备写入回执,不是共享汇总;`changed=true` 不保证汇总前进。按群公共顺序单调更新,重复或旧位置返回 `changed=false`。每个 RPC 只等待本次依赖的写入提交;跨多个数据库批次时,失败不回滚先前提交,原样幂等重试可收敛。`group.read` 与投递 `group.ack_messages/ack_events` 独立。
1892
+
1893
+ ## group.read_state
1894
+
1895
+ 可选字段为 `scope`、`group_id`、`topic_key` 和当前认证 `aid`。`scope` 缺省或为空时按 `group` 处理,非空值只能为 `group`;`aid` 非空值只能等于认证 AID。显式非字符串或 `null` 拒绝。查询返回有权限的群状态;提供 group ID 时先解析为 canonical ID 并校验成员权限。未提供 group ID 时通过完整成员目录发现远域群并逐群合并,保留 topic 过滤,不受默认群列表分页限制。响应始终有 `states`,只有一项时顶层镜像该项。每项包含 `scope=group`、`group_id`、`topic_key`、`last_read_message_id`、`last_read_order`、`current_device_seq`、`mapping_status` 和毫秒 `updated_at`。
1896
+
1897
+ `last_read_order` 为群公共消息顺序,用于缓存乱序保护。`current_device_seq` 只映射当前设备,无法映射返回 `null`。`resolved` 表示映射成功;`not_received` 表示公共位置已知但当前设备无投递记录;`unresolved` 表示公共位置无法解析。未知位置首次上报保存待解析事实,不广播汇总前进;未知不能覆盖已知,不以消息 ID 字典序猜测两个未知位置;晚到公共位置对仍匹配该消息且 order=0 的事实条件持久回填,不能只更新缓存或覆盖并发前进的事实。
1898
+
1899
+ 网络 JSON 的公共顺序和 seq 为整数,Gateway 本域服务及 federation 回程必须无损保留;TS/JS 的 `last_read_order`、非空 `current_device_seq` 在安全整数范围内是 number,超出时是精确十进制字符串。四端 facade 分别为 Python `group.read/read_state`、TS/JS `group.read/readState`、Go `Group().Read/ReadState`。四个已读门面保留显式 `None/null/nil` 字段供服务端拒绝,不改变其他门面的空值处理。写入回执不进入共享缓存,旧事件不交付应用,同位置事件保留设备映射;未知顺序不按时间或 ID 猜测前进。该接口只返回同一 AID 的设备汇总,不返回其它设备明细,也不保存 Group 事件流的已读状态。
1900
+
1901
+ ## group.read_changed
1902
+
1903
+ 数据库提交成功且 AID 汇总前进后,SDK 收到 `group.read_changed`。包含 `owner_aid`、`scope=group`、`group_id`、`topic_key`、`last_read_message_id`、`last_read_order` 和 `updated_at`。`owner_aid` 必须非空,SDK 要求其等于当前身份且 `scope=group` 匹配原事件。Gateway 即使收到显式 route 也只向该 AID 分发,校验 Kernel 转发的可信 Group 来源;群所属域可通过 federation 发送给该外域成员 AID,不能广播给其他群成员,来源绑定 canonical 群 ID 的 issuer。事件 ID 对 JSON 数组 `[owner_aid, group_id, topic_key, last_read_message_id]` 计算 SHA-256,不包含 `last_read_order`,失败日志不泄露 topic。事件不进入 Pull 队列,缺失依靠 `group.read_state` 补偿。
1904
+
1905
+ SDK 保留成功查询的原过滤范围,包括空结果、全量及按群查询。连接成功后补偿并在 SDK 本地发布 `read_state_sync`,含 `owner_aid`、去重 `states` 及 `{method, params, error}` 错误项;消息 `background_sync=false` 不关闭该补偿。AID/device 切换清理缓存及登记项;旧身份在途结果按身份代际隔离,A→B→A 也不写当前缓存或补偿完成事件,原 RPC 调用仍可返回结果。应用应在 connect 前订阅,完成事件的状态与映射处理见 [跨设备已读未读 SDK 集成指南](../跨设备已读未读SDK集成指南.md)。
1906
+
1871
1907
  ## 事件
1872
1908
 
1873
1909
  ### event/group.created
@@ -1937,9 +1973,9 @@ SDK 交付给应用层的群事件信封字段统一放在 `envelope`。0.5.x
1937
1973
  | `member_added` | 成员加入 |
1938
1974
  | `member_left` | 成员退出 |
1939
1975
  | `member_removed` | 成员被踢出 |
1940
- | `role_changed` | 角色变更 |
1941
- | `owner_transfer_rekey_pending` | 群主转让已发起,等待新群主完成群身份换钥 |
1942
- | `owner_transferred` | 群主转让 |
1976
+ | `role_changed` | 角色变更 |
1977
+ | `owner_transfer_rekey_pending` | 群主转让已发起,等待新群主完成群身份换钥 |
1978
+ | `owner_transferred` | 群主转让 |
1943
1979
  | `rules_updated` | 规则更新 |
1944
1980
  | `announcement_updated` | 公告更新 |
1945
1981
  | `join_requested` | 收到入群申请 |
@@ -1950,10 +1986,10 @@ SDK 交付给应用层的群事件信封字段统一放在 `envelope`。0.5.x
1950
1986
  | `invite_code_created` | 邀请码创建 |
1951
1987
  | `invite_code_used` | 邀请码使用 |
1952
1988
  | `invite_code_revoked` | 邀请码撤销 |
1953
- | `member_banned` | 成员封禁 |
1954
- | `member_unbanned` | 成员解封 |
1955
- | `member_blocked` | 成员被屏蔽 |
1956
- | `member_unblocked` | 成员取消屏蔽 |
1989
+ | `member_banned` | 成员封禁 |
1990
+ | `member_unbanned` | 成员解封 |
1991
+ | `member_blocked` | 成员被屏蔽 |
1992
+ | `member_unblocked` | 成员取消屏蔽 |
1957
1993
  | `suspended` | 群组暂停 |
1958
1994
  | `resumed` | 群组恢复 |
1959
1995
  | `dissolved` | 群组解散 |
@@ -2039,46 +2075,46 @@ SDK 收到新 Head 后自动同步最新消息页并逐条解密;若 A 与 T
2039
2075
  }
2040
2076
  ```
2041
2077
 
2042
- SDK 交付给应用层的 `payload` 是明文业务 JSON 对象;群消息信封字段统一放在 `envelope`。`envelope` 只保留可转发的归一化元数据,`from` 由 `sender_aid` 归一化而来,`timestamp` 由 `created_at` / `t_server` 归一化而来。当前仍保留顶层 `group_id` / `seq` / `message_id` / `sender_aid` / `mention_mode` 等字段;新代码应优先通过 `msg["envelope"]["from"]`、`msg["envelope"]["timestamp"]` 等路径访问。Gateway 可能附加 `proximity` 及 `same_device` / `same_egress_ip` / `same_network`,表示由 Gateway 基于连接上下文判断的近端关系提示,不参与 E2EE AAD 或业务鉴权。
2043
-
2044
- ### delivery.changed
2045
-
2046
- 成功交付 `group.message_created` 后,四个 SDK 会通过本地 `delivery.changed` 事件通知应用合并刷新群会话 UI。群变更项使用 canonical group AID:
2047
-
2048
- ```json
2049
- {
2050
- "trigger": "pull_drained",
2051
- "changes": [
2052
- {"namespace": "group:g-abc123.agentid.pub", "delivered_count": 50}
2053
- ]
2054
- }
2055
- ```
2056
-
2057
- ### group.invite_member
2058
-
2059
- 创建指定 AID 的待处理邀请,不写入正式成员表。公开群允许任意正式成员,非公开群仅 owner/admin;同一群、目标和邀请者重复调用幂等返回原记录。
2060
-
2061
- **参数**:`group_id`、`aid`(或 `invitee_aid`)必填;`member_type` 可选(`human` / `ai`,默认 `human`)。
2062
-
2063
- ### group.list_my_invites
2064
-
2065
- 列出当前认证 AID 收到的待处理邀请,按群和目标 AID 聚合;支持 `page`、`size` 分页参数。
2066
-
2067
- ### group.accept_invite
2068
-
2069
- 被邀请 AID 以 `invite_id` 接受聚合邀请;成功后才原子写入正式成员表。
2070
-
2071
- ### group.reject_invite
2072
-
2073
- 被邀请 AID 以 `invite_id` 拒绝聚合邀请,不写入正式成员表。
2074
-
2075
- ### group.revoke_invite
2076
-
2077
- 原邀请发出者以 `invite_id` 撤回自己的待处理邀请。撤回、接受、拒绝和过期是互斥终态转换。
2078
-
2079
- 该事件不是服务端 `event/group.*`。多个群和 P2P 的 Pull 共用当前 `AUNClient` 的全局排空边界,因此一次 `pull_drained` 可以包含多个 `group:<canonical-group-aid>` 和 `p2p` 变更;有效 Push / Inline Push 则在原群消息事件处理完成后实时通知。完整 payload、折叠和零通知条件见 [06-API手册:delivery.changed](06-API手册.md#deliverychanged)。
2080
-
2081
- ### event/group.message_recalled
2078
+ SDK 交付给应用层的 `payload` 是明文业务 JSON 对象;群消息信封字段统一放在 `envelope`。`envelope` 只保留可转发的归一化元数据,`from` 由 `sender_aid` 归一化而来,`timestamp` 由 `created_at` / `t_server` 归一化而来。当前仍保留顶层 `group_id` / `seq` / `message_id` / `sender_aid` / `mention_mode` 等字段;新代码应优先通过 `msg["envelope"]["from"]`、`msg["envelope"]["timestamp"]` 等路径访问。Gateway 可能附加 `proximity` 及 `same_device` / `same_egress_ip` / `same_network`,表示由 Gateway 基于连接上下文判断的近端关系提示,不参与 E2EE AAD 或业务鉴权。
2079
+
2080
+ ### delivery.changed
2081
+
2082
+ 成功交付 `group.message_created` 后,四个 SDK 会通过本地 `delivery.changed` 事件通知应用合并刷新群会话 UI。群变更项使用 canonical group AID:
2083
+
2084
+ ```json
2085
+ {
2086
+ "trigger": "pull_drained",
2087
+ "changes": [
2088
+ {"namespace": "group:g-abc123.agentid.pub", "delivered_count": 50}
2089
+ ]
2090
+ }
2091
+ ```
2092
+
2093
+ ### group.invite_member
2094
+
2095
+ 创建指定 AID 的待处理邀请,不写入正式成员表。公开群允许任意正式成员,非公开群仅 owner/admin;同一群、目标和邀请者重复调用幂等返回原记录。
2096
+
2097
+ **参数**:`group_id`、`aid`(或 `invitee_aid`)必填;`member_type` 可选(`human` / `ai`,默认 `human`)。
2098
+
2099
+ ### group.list_my_invites
2100
+
2101
+ 列出当前认证 AID 收到的待处理邀请,按群和目标 AID 聚合;支持 `page`、`size` 分页参数。
2102
+
2103
+ ### group.accept_invite
2104
+
2105
+ 被邀请 AID 以 `invite_id` 接受聚合邀请;成功后才原子写入正式成员表。
2106
+
2107
+ ### group.reject_invite
2108
+
2109
+ 被邀请 AID 以 `invite_id` 拒绝聚合邀请,不写入正式成员表。
2110
+
2111
+ ### group.revoke_invite
2112
+
2113
+ 原邀请发出者以 `invite_id` 撤回自己的待处理邀请。撤回、接受、拒绝和过期是互斥终态转换。
2114
+
2115
+ 该事件不是服务端 `event/group.*`。多个群和 P2P 的 Pull 共用当前 `AUNClient` 的全局排空边界,因此一次 `pull_drained` 可以包含多个 `group:<canonical-group-aid>` 和 `p2p` 变更;有效 Push / Inline Push 则在原群消息事件处理完成后实时通知。完整 payload、折叠和零通知条件见 [06-API手册:delivery.changed](06-API手册.md#deliverychanged)。
2116
+
2117
+ ### event/group.message_recalled
2082
2118
 
2083
2119
  群消息撤回后推送给所有在线成员(与 pull 双 tombstone 兜底互补)。在线 push 是实时通道,双 tombstone 是离线 / 未读 / push 丢失时的可靠性兜底;两者最终一致,SDK 去重保证应用层只感知一次。
2084
2120