@agentunion/fastaun-browser 0.4.3 → 0.4.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/CHANGELOG.md +190 -178
- package/_packed_docs/AUN_SDK_0.4.0_/350/256/276/350/256/241/345/257/271/346/257/224/345/210/206/346/236/220.md +194 -194
- package/_packed_docs/AUN_SDK_/351/207/215/346/236/204/345/256/236/346/226/275/350/256/241/345/210/222.md +596 -596
- package/_packed_docs/AUN_SDK_/351/207/215/346/236/204/350/256/276/350/256/241/346/226/271/346/241/210_v3.md +1698 -1697
- package/_packed_docs/CHANGELOG.md +190 -178
- package/_packed_docs/INDEX.md +17 -17
- package/_packed_docs/KITE_DOCS_GUIDE.md +11 -11
- package/_packed_docs/agent.md/SCHEMA.md +49 -49
- package/_packed_docs/agent.md/examples/signed-openclaw-lobster.md +22 -22
- 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 +327 -327
- package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +686 -686
- package/_packed_docs/design/2026-05-22-aun-rpc-trace-enhancement.md +542 -542
- package/_packed_docs/design/E2EE_V2/347/256/200/345/214/226/344/270/2721DH/345/212/240Per-AID_Wrap/346/226/271/346/241/210.md +124 -124
- package/_packed_docs/design//350/267/250/350/257/255/350/250/200/345/256/271/345/231/250E2E/346/265/213/350/257/225/346/226/271/346/241/210.md +665 -665
- 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 +2 -2
- package/_packed_docs/protocol/14-/344/272/244/344/272/222/346/234/272/345/210/266-/345/223/215/345/272/224/346/250/241/345/274/217/344/270/216/350/207/252/344/270/273/346/250/241/345/274/217.md +170 -170
- package/_packed_docs/protocol/15-/347/246/273/347/272/277/346/216/250/351/200/201/351/200/232/347/237/245/345/215/217/350/256/256.md +419 -419
- package/_packed_docs/protocol/README.md +1 -1
- package/_packed_docs/protocol/aun-docs-guide.md +1 -1
- package/_packed_docs/protocol//351/231/204/345/275/225A-/346/234/257/350/257/255/350/241/250.md +15 -15
- package/_packed_docs/protocol//351/231/204/345/275/225B-/346/211/251/345/261/225/346/200/247/346/214/207/345/215/227.md +4 -4
- package/_packed_docs/protocol//351/231/204/345/275/225J-/345/256/242/346/210/267/347/253/257/346/216/245/345/205/245/347/244/272/344/276/213.md +98 -98
- package/_packed_docs/protocol//351/231/204/345/275/225M-JWT/350/256/244/350/257/201/345/256/236/347/216/260/346/214/207/345/215/227.md +46 -46
- package/_packed_docs/protocol//351/231/204/345/275/225N-/345/210/206/345/270/203/345/274/217Trace/345/215/217/350/256/256.md +257 -257
- package/_packed_docs/python-sdk-v2-only-changelog.md +189 -189
- package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +1 -1
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +1 -1
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +1 -0
- package/_packed_docs/sdk/09-payload-reference.md +13 -13
- package/_packed_docs/sdk/E2EE_V2/346/266/210/346/201/257/351/200/232/344/277/241/346/227/266/345/272/217/345/233/276.md +171 -171
- package/dist/aid.d.ts +2 -1
- package/dist/aid.d.ts.map +1 -1
- package/dist/aid.js +7 -6
- package/dist/aid.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +4 -0
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +237 -149
- package/dist/client.d.ts +7 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +238 -153
- package/dist/client.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,189 +1,189 @@
|
|
|
1
|
-
# Python SDK V2-Only 改动清单
|
|
2
|
-
|
|
3
|
-
基线:`d8b79f44` (v0.2.20 之后,master_1.0.0 分支)
|
|
4
|
-
日期:2026-05-20
|
|
5
|
-
|
|
6
|
-
## 一、源码改动(`python/src/aun_core/`)
|
|
7
|
-
|
|
8
|
-
### 1. client.py:8588 行 → 4502 行(净删 4086 行)
|
|
9
|
-
|
|
10
|
-
#### 删除的 V1 E2EE 代码(共 ~95 个方法)
|
|
11
|
-
|
|
12
|
-
**V1 P2P 加密:**
|
|
13
|
-
- `_send_encrypted`, `_build_self_sync_copies`, `_build_recipient_device_copies`
|
|
14
|
-
- `_encrypt_copy_payload`, `_ensure_encrypt_result`, `_resolve_self_copy_peer_cert`
|
|
15
|
-
- `_log_e2ee_error`
|
|
16
|
-
|
|
17
|
-
**V1 群组加密:**
|
|
18
|
-
- `_send_group_encrypted`, `_put_group_thought_encrypted`, `_put_message_thought_encrypted`
|
|
19
|
-
- `_call_group_encrypted_rpc`, `_prepare_group_encrypted_rpc_params`
|
|
20
|
-
|
|
21
|
-
**V1 Epoch 管理:**
|
|
22
|
-
- `_recover_group_epoch_key`, `_do_recover_group_epoch_key`, `_try_recover_epoch_key_from_server`
|
|
23
|
-
- `_recover_initial_group_epoch_if_needed`, `_request_group_key_from_candidates`
|
|
24
|
-
- `_request_group_key_from_online`, `_request_group_key_from`
|
|
25
|
-
- `_group_epoch_secret_ready_for_recovery`, `_pending_group_secret_still_current`
|
|
26
|
-
- `_ensure_group_epoch_ready`, `_wait_for_group_membership_epoch_floor`
|
|
27
|
-
- `_committed_group_epoch`, `_committed_group_epoch_state`
|
|
28
|
-
- `_ensure_committed_group_secret_for_send`, `_committed_rotation_membership_gap`
|
|
29
|
-
|
|
30
|
-
**V1 密钥控制面:**
|
|
31
|
-
- `_try_handle_group_key_message`, `_verify_active_group_rotation_distribution`
|
|
32
|
-
- `_verify_group_key_response_epoch`, `_discard_group_distribution_if_stale`
|
|
33
|
-
- `_ack_group_rotation_key`
|
|
34
|
-
|
|
35
|
-
**V1 Epoch 轮换:**
|
|
36
|
-
- `_build_rotation_signature`, `_attach_rotation_id`, `_build_epoch_encrypted_keys`
|
|
37
|
-
- `_distribute_group_epoch_key`, `_heartbeat_group_rotation`, `_abort_group_rotation`
|
|
38
|
-
- `_schedule_group_rotation_retry`, `_sync_epoch_to_server`
|
|
39
|
-
- `_maybe_lead_rotate_group_epoch`, `_ranked_group_rotation_candidates`, `_rotate_group_epoch`
|
|
40
|
-
- `_delayed_rotate_after_join`, `_maybe_backfill_key_to_joined_member`
|
|
41
|
-
- `_distribute_key_to_new_member`, `_start_group_epoch_tasks`
|
|
42
|
-
- `_is_rotation_leader`, `_group_epoch_rotate_loop`, `_group_epoch_cleanup_loop`
|
|
43
|
-
|
|
44
|
-
**V1 解密:**
|
|
45
|
-
- `_decrypt_messages`, `_decrypt_single_message`
|
|
46
|
-
- `_decrypt_group_message`, `_decrypt_group_messages`
|
|
47
|
-
- `_decrypt_group_thoughts`, `_decrypt_message_thoughts`
|
|
48
|
-
|
|
49
|
-
**V1 Pending queue:**
|
|
50
|
-
- `_enqueue_pending_decrypt`, `_schedule_retry_pending_decrypt_msgs`
|
|
51
|
-
- `_retry_pending_decrypt_msgs`, `_schedule_recovery_timeout`, `_cleanup_group_state`
|
|
52
|
-
|
|
53
|
-
**V1 Prekey:**
|
|
54
|
-
- `_upload_prekey`, `_prekey_refresh_loop`, `_start_prekey_refresh_task`
|
|
55
|
-
- `_schedule_prekey_replenish_if_consumed`, `_invalidate_peer_prekey_cache`
|
|
56
|
-
- `_fetch_peer_prekeys`, `_fetch_peer_prekey`, `_normalize_peer_prekeys`
|
|
57
|
-
- `_refresh_peer_prekeys`, `_clear_peer_cert_cache`
|
|
58
|
-
|
|
59
|
-
**V1 错误辅助:**
|
|
60
|
-
- `_is_group_epoch_too_old_error`, `_is_group_epoch_rotation_pending_error`
|
|
61
|
-
- `_is_group_epoch_changed_during_send_error`, `_is_recoverable_group_epoch_error`
|
|
62
|
-
- `_is_expected_group_rotation_skip_error`
|
|
63
|
-
|
|
64
|
-
**V1 成员轮换辅助:**
|
|
65
|
-
- `_membership_rotation_trigger_id`, `_membership_rotation_changed`
|
|
66
|
-
- `_membership_rotation_expected_epoch`, `_extract_group_id_from_result`
|
|
67
|
-
- `_get_group_member_aids`, `_local_group_members_match`, `_extract_group_join_mode`
|
|
68
|
-
- `_group_allows_member_epoch_rotation`, `_group_key_recovery_candidates`
|
|
69
|
-
- `_joined_member_aids_from_payload`
|
|
70
|
-
|
|
71
|
-
**V1 群组推送处理:**
|
|
72
|
-
- `_process_and_publish_group_message`, `_auto_pull_group_messages`, `_fill_group_gap`
|
|
73
|
-
|
|
74
|
-
**V1 公开 API:**
|
|
75
|
-
- `e2ee` property, `group_e2ee` property
|
|
76
|
-
- `send_v2`, `pull_v2`, `ack_v2`, `send_group_v2`, `pull_group_v2`, `ack_group_v2`
|
|
77
|
-
(独立方法合并进 `call()` 路由)
|
|
78
|
-
|
|
79
|
-
#### 删除的 V1 实例变量
|
|
80
|
-
|
|
81
|
-
- `self._e2ee` (E2EEManager)
|
|
82
|
-
- `self._group_e2ee` (GroupE2EEManager)
|
|
83
|
-
- `self._pending_decrypt_msgs`
|
|
84
|
-
- `self._recovery_timeout_scheduled`
|
|
85
|
-
- `self._group_epoch_rotation_inflight`
|
|
86
|
-
- `self._group_epoch_rotation_retry_tasks`
|
|
87
|
-
- `self._group_epoch_recovery_inflight`
|
|
88
|
-
- `self._group_membership_rotation_done`
|
|
89
|
-
- `self._group_member_key_backfill_done`
|
|
90
|
-
|
|
91
|
-
#### 新增/修改的逻辑
|
|
92
|
-
|
|
93
|
-
- `_on_raw_group_message_created`:简化为明文消息透传 + seq 跟踪(不再做 V1 解密)
|
|
94
|
-
- `_process_and_publish_message`:移除 V1 解密调用,明文直接透传
|
|
95
|
-
- `_on_raw_group_changed`:移除 V1 epoch 轮换编排,保留 V2 `_v2_auto_propose_state` + event gap 检测
|
|
96
|
-
- `call()` 中 `message.pull` / `group.pull` 后处理:移除 V1 解密,保留 seq 跟踪 + auto-ack
|
|
97
|
-
- `_stop_background_tasks`:移除 V1 epoch 任务清理
|
|
98
|
-
- `_start_background_tasks`:移除 `_start_group_epoch_tasks()` 调用
|
|
99
|
-
- V2 解密元数据:`e2ee` 字段增加 `encryption_mode` 和 `forward_secrecy`
|
|
100
|
-
- V2 group pull:移除返回值去重(pull 始终返回所有解密成功的消息)
|
|
101
|
-
|
|
102
|
-
### 2. seq_tracker.py:+14 行
|
|
103
|
-
|
|
104
|
-
- `on_pull_result` 新增 `after_seq` 参数
|
|
105
|
-
- gap fill 场景(`after_seq == contiguous_seq`):直接把 pull 到的最大 seq 作为新 `contiguous_seq`,跳过服务端永久空洞
|
|
106
|
-
|
|
107
|
-
### 3. `__init__.py`:无变化(`ProtectedHeaders` 保留)
|
|
108
|
-
|
|
109
|
-
### 4. `e2ee.py`:不动(3544 行保留作为参考)
|
|
110
|
-
|
|
111
|
-
### 5. 保留的 e2ee.py 引用(非 E2EE 加解密)
|
|
112
|
-
|
|
113
|
-
- `from .e2ee import ProtectedHeaders` — 纯数据类,V2 也用
|
|
114
|
-
- `from .e2ee import compute_state_hash` (2处) — 群组 state hash 验证工具函数
|
|
115
|
-
|
|
116
|
-
## 二、测试改动(`python/tests/`)
|
|
117
|
-
|
|
118
|
-
### 删除的测试文件(纯 V1 E2EE)
|
|
119
|
-
|
|
120
|
-
- `e2e_test_epoch_key_server.py` — V1 epoch key 服务端托管
|
|
121
|
-
- `integration_test_e2ee.py` — V1 P2P E2EE 集成
|
|
122
|
-
- `integration_test_multi_device_e2ee.py` — V1 多设备 E2EE
|
|
123
|
-
- `unit/test_client_group_e2ee.py` — V1 群组 E2EE 单元测试(93 个用例)
|
|
124
|
-
|
|
125
|
-
### 删除的测试用例(从现有文件中移除)
|
|
126
|
-
|
|
127
|
-
- `test_client.py`:24 个 V1 测试(prekey、send_encrypted V1、decrypt_group 等)
|
|
128
|
-
- `test_py_issues.py`:`TestPY004PrekeyRefreshLoop`
|
|
129
|
-
- `test_py_issues_batch2.py`:`TestPY001DecryptFailStillAutoAck`、`TestPY002KeyRecoveryRetry`、`TestPY003DissolveCleanup`、`TestPY005RotateLoopLeaderElection`
|
|
130
|
-
- `test_py_issues_batch3.py`:`TestPY002PushedSeqsLimit`、`TestPY005EpochWait`
|
|
131
|
-
|
|
132
|
-
### 修改的测试
|
|
133
|
-
|
|
134
|
-
- `test_client.py`:`test_e2ee_property` 改为断言 `e2ee` 属性不存在
|
|
135
|
-
- `integration_test_storage.py`:自定义 redirect handler 支持 PUT 302 重定向
|
|
136
|
-
|
|
137
|
-
## 三、服务端改动(`extensions/services/`)
|
|
138
|
-
|
|
139
|
-
| 文件 | 改动 |
|
|
140
|
-
|------|------|
|
|
141
|
-
| `gateway/entry.py` | kernel event 订阅补全 V2 事件(fallback);`_handle_event_notification` 路由补全 V2 事件 |
|
|
142
|
-
| `gateway/ws_server.py` | `_dispatch_event_from_service` 白名单补全 `group.state_committed` |
|
|
143
|
-
| `gateway/relay.py` | `_should_forward_event` 补全 `group.state_committed`;`_V2_ONLY_GROUP_METHODS` 补全 `propose_state/confirm_state/get_proposal` |
|
|
144
|
-
| `message/entry.py` | `AUN_DIRECT_EVENT_MESSAGE` 默认改为 True;V2 send 返回 status 对齐 V1 语义(`delivered`/`sent`) |
|
|
145
|
-
| `group/entry.py` | `AUN_DIRECT_EVENT_GROUP` 默认改为 True;`_targets_for_group_event` / `is_client_event` 补全 `group.state_committed`;`_rpc_v2_pull` / `_rpc_v2_ack` 补全成员权限检查 |
|
|
146
|
-
|
|
147
|
-
## 四、Bug 修复(需要其它 SDK 对齐)
|
|
148
|
-
|
|
149
|
-
### BUG-1: gap fill 时 contiguous_seq 卡死
|
|
150
|
-
|
|
151
|
-
**根因:** `on_pull_result` 从 `contiguous_seq` 开始 pull,如果服务端返回的消息跳过了某些 seq(永久空洞:竞态跳跃/未持久化/过期清理),`_try_advance` 逐个检查时会卡在第一个缺失的 seq 上,永远无法推进。新消息被阻塞在 SDK 内部有序队列中,上层收不到。
|
|
152
|
-
|
|
153
|
-
**修复:** `on_pull_result` 新增 `after_seq` 参数。当 `after_seq == contiguous_seq`(gap fill 场景)时,直接把 pull 到的最大 seq 作为新的 `contiguous_seq`。
|
|
154
|
-
|
|
155
|
-
**影响范围:** P2P pull、group pull、event pull 三条路径。
|
|
156
|
-
|
|
157
|
-
### BUG-2: V2 group pull 返回值去重导致手动 pull 拿不到已 push 的消息
|
|
158
|
-
|
|
159
|
-
**根因:** `_pull_group_v2_internal` 中 `_is_published_seq` 去重导致已通过 push 自动 pull 消费的消息在手动 pull 时被跳过,返回空列表。
|
|
160
|
-
|
|
161
|
-
**修复:** pull 返回值不再做 `_is_published_seq` 去重。`_publish_ordered_message` 内部仍做事件投递去重(防止重复触发应用层回调),但 pull 的返回值始终包含所有解密成功的消息。
|
|
162
|
-
|
|
163
|
-
### BUG-3: V2 message.send 返回 status 不对齐 V1 语义
|
|
164
|
-
|
|
165
|
-
**根因:** V2 send 返回 `"status": "accepted"`,但 SDK 和应用层已按 V1 语义(`sent`/`delivered`)实现。
|
|
166
|
-
|
|
167
|
-
**修复:** 服务端 `delivered_count > 0` 时返回 `delivered`,否则返回 `sent`。
|
|
168
|
-
|
|
169
|
-
### BUG-4: V2 解密元数据缺少 encryption_mode
|
|
170
|
-
|
|
171
|
-
**根因:** V2 解密后 `e2ee` 字段只有 `version` + `suite`,缺少 `encryption_mode` 和 `forward_secrecy`,导致依赖这些字段的测试/应用层判断失败。
|
|
172
|
-
|
|
173
|
-
**修复:** 补全 `encryption_mode: "v2_{suite}"` 和 `forward_secrecy: True`。
|
|
174
|
-
|
|
175
|
-
## 五、验证结果
|
|
176
|
-
|
|
177
|
-
| 测试 | 结果 |
|
|
178
|
-
|------|------|
|
|
179
|
-
| 单元测试 | 501 passed |
|
|
180
|
-
| V2 P2P E2EE | 12/12 |
|
|
181
|
-
| V2 Group E2EE | 8/8 |
|
|
182
|
-
| V2 Multi-device | 6/6 |
|
|
183
|
-
| Echo | 5/5 |
|
|
184
|
-
| Message Ack | 4/4 |
|
|
185
|
-
| Storage | 4/4 |
|
|
186
|
-
| 双域明文 | PASS |
|
|
187
|
-
| 双域加密 | PASS |
|
|
188
|
-
| 双域离线 | PASS |
|
|
189
|
-
| 双域群组 | 2/2 |
|
|
1
|
+
# Python SDK V2-Only 改动清单
|
|
2
|
+
|
|
3
|
+
基线:`d8b79f44` (v0.2.20 之后,master_1.0.0 分支)
|
|
4
|
+
日期:2026-05-20
|
|
5
|
+
|
|
6
|
+
## 一、源码改动(`python/src/aun_core/`)
|
|
7
|
+
|
|
8
|
+
### 1. client.py:8588 行 → 4502 行(净删 4086 行)
|
|
9
|
+
|
|
10
|
+
#### 删除的 V1 E2EE 代码(共 ~95 个方法)
|
|
11
|
+
|
|
12
|
+
**V1 P2P 加密:**
|
|
13
|
+
- `_send_encrypted`, `_build_self_sync_copies`, `_build_recipient_device_copies`
|
|
14
|
+
- `_encrypt_copy_payload`, `_ensure_encrypt_result`, `_resolve_self_copy_peer_cert`
|
|
15
|
+
- `_log_e2ee_error`
|
|
16
|
+
|
|
17
|
+
**V1 群组加密:**
|
|
18
|
+
- `_send_group_encrypted`, `_put_group_thought_encrypted`, `_put_message_thought_encrypted`
|
|
19
|
+
- `_call_group_encrypted_rpc`, `_prepare_group_encrypted_rpc_params`
|
|
20
|
+
|
|
21
|
+
**V1 Epoch 管理:**
|
|
22
|
+
- `_recover_group_epoch_key`, `_do_recover_group_epoch_key`, `_try_recover_epoch_key_from_server`
|
|
23
|
+
- `_recover_initial_group_epoch_if_needed`, `_request_group_key_from_candidates`
|
|
24
|
+
- `_request_group_key_from_online`, `_request_group_key_from`
|
|
25
|
+
- `_group_epoch_secret_ready_for_recovery`, `_pending_group_secret_still_current`
|
|
26
|
+
- `_ensure_group_epoch_ready`, `_wait_for_group_membership_epoch_floor`
|
|
27
|
+
- `_committed_group_epoch`, `_committed_group_epoch_state`
|
|
28
|
+
- `_ensure_committed_group_secret_for_send`, `_committed_rotation_membership_gap`
|
|
29
|
+
|
|
30
|
+
**V1 密钥控制面:**
|
|
31
|
+
- `_try_handle_group_key_message`, `_verify_active_group_rotation_distribution`
|
|
32
|
+
- `_verify_group_key_response_epoch`, `_discard_group_distribution_if_stale`
|
|
33
|
+
- `_ack_group_rotation_key`
|
|
34
|
+
|
|
35
|
+
**V1 Epoch 轮换:**
|
|
36
|
+
- `_build_rotation_signature`, `_attach_rotation_id`, `_build_epoch_encrypted_keys`
|
|
37
|
+
- `_distribute_group_epoch_key`, `_heartbeat_group_rotation`, `_abort_group_rotation`
|
|
38
|
+
- `_schedule_group_rotation_retry`, `_sync_epoch_to_server`
|
|
39
|
+
- `_maybe_lead_rotate_group_epoch`, `_ranked_group_rotation_candidates`, `_rotate_group_epoch`
|
|
40
|
+
- `_delayed_rotate_after_join`, `_maybe_backfill_key_to_joined_member`
|
|
41
|
+
- `_distribute_key_to_new_member`, `_start_group_epoch_tasks`
|
|
42
|
+
- `_is_rotation_leader`, `_group_epoch_rotate_loop`, `_group_epoch_cleanup_loop`
|
|
43
|
+
|
|
44
|
+
**V1 解密:**
|
|
45
|
+
- `_decrypt_messages`, `_decrypt_single_message`
|
|
46
|
+
- `_decrypt_group_message`, `_decrypt_group_messages`
|
|
47
|
+
- `_decrypt_group_thoughts`, `_decrypt_message_thoughts`
|
|
48
|
+
|
|
49
|
+
**V1 Pending queue:**
|
|
50
|
+
- `_enqueue_pending_decrypt`, `_schedule_retry_pending_decrypt_msgs`
|
|
51
|
+
- `_retry_pending_decrypt_msgs`, `_schedule_recovery_timeout`, `_cleanup_group_state`
|
|
52
|
+
|
|
53
|
+
**V1 Prekey:**
|
|
54
|
+
- `_upload_prekey`, `_prekey_refresh_loop`, `_start_prekey_refresh_task`
|
|
55
|
+
- `_schedule_prekey_replenish_if_consumed`, `_invalidate_peer_prekey_cache`
|
|
56
|
+
- `_fetch_peer_prekeys`, `_fetch_peer_prekey`, `_normalize_peer_prekeys`
|
|
57
|
+
- `_refresh_peer_prekeys`, `_clear_peer_cert_cache`
|
|
58
|
+
|
|
59
|
+
**V1 错误辅助:**
|
|
60
|
+
- `_is_group_epoch_too_old_error`, `_is_group_epoch_rotation_pending_error`
|
|
61
|
+
- `_is_group_epoch_changed_during_send_error`, `_is_recoverable_group_epoch_error`
|
|
62
|
+
- `_is_expected_group_rotation_skip_error`
|
|
63
|
+
|
|
64
|
+
**V1 成员轮换辅助:**
|
|
65
|
+
- `_membership_rotation_trigger_id`, `_membership_rotation_changed`
|
|
66
|
+
- `_membership_rotation_expected_epoch`, `_extract_group_id_from_result`
|
|
67
|
+
- `_get_group_member_aids`, `_local_group_members_match`, `_extract_group_join_mode`
|
|
68
|
+
- `_group_allows_member_epoch_rotation`, `_group_key_recovery_candidates`
|
|
69
|
+
- `_joined_member_aids_from_payload`
|
|
70
|
+
|
|
71
|
+
**V1 群组推送处理:**
|
|
72
|
+
- `_process_and_publish_group_message`, `_auto_pull_group_messages`, `_fill_group_gap`
|
|
73
|
+
|
|
74
|
+
**V1 公开 API:**
|
|
75
|
+
- `e2ee` property, `group_e2ee` property
|
|
76
|
+
- `send_v2`, `pull_v2`, `ack_v2`, `send_group_v2`, `pull_group_v2`, `ack_group_v2`
|
|
77
|
+
(独立方法合并进 `call()` 路由)
|
|
78
|
+
|
|
79
|
+
#### 删除的 V1 实例变量
|
|
80
|
+
|
|
81
|
+
- `self._e2ee` (E2EEManager)
|
|
82
|
+
- `self._group_e2ee` (GroupE2EEManager)
|
|
83
|
+
- `self._pending_decrypt_msgs`
|
|
84
|
+
- `self._recovery_timeout_scheduled`
|
|
85
|
+
- `self._group_epoch_rotation_inflight`
|
|
86
|
+
- `self._group_epoch_rotation_retry_tasks`
|
|
87
|
+
- `self._group_epoch_recovery_inflight`
|
|
88
|
+
- `self._group_membership_rotation_done`
|
|
89
|
+
- `self._group_member_key_backfill_done`
|
|
90
|
+
|
|
91
|
+
#### 新增/修改的逻辑
|
|
92
|
+
|
|
93
|
+
- `_on_raw_group_message_created`:简化为明文消息透传 + seq 跟踪(不再做 V1 解密)
|
|
94
|
+
- `_process_and_publish_message`:移除 V1 解密调用,明文直接透传
|
|
95
|
+
- `_on_raw_group_changed`:移除 V1 epoch 轮换编排,保留 V2 `_v2_auto_propose_state` + event gap 检测
|
|
96
|
+
- `call()` 中 `message.pull` / `group.pull` 后处理:移除 V1 解密,保留 seq 跟踪 + auto-ack
|
|
97
|
+
- `_stop_background_tasks`:移除 V1 epoch 任务清理
|
|
98
|
+
- `_start_background_tasks`:移除 `_start_group_epoch_tasks()` 调用
|
|
99
|
+
- V2 解密元数据:`e2ee` 字段增加 `encryption_mode` 和 `forward_secrecy`
|
|
100
|
+
- V2 group pull:移除返回值去重(pull 始终返回所有解密成功的消息)
|
|
101
|
+
|
|
102
|
+
### 2. seq_tracker.py:+14 行
|
|
103
|
+
|
|
104
|
+
- `on_pull_result` 新增 `after_seq` 参数
|
|
105
|
+
- gap fill 场景(`after_seq == contiguous_seq`):直接把 pull 到的最大 seq 作为新 `contiguous_seq`,跳过服务端永久空洞
|
|
106
|
+
|
|
107
|
+
### 3. `__init__.py`:无变化(`ProtectedHeaders` 保留)
|
|
108
|
+
|
|
109
|
+
### 4. `e2ee.py`:不动(3544 行保留作为参考)
|
|
110
|
+
|
|
111
|
+
### 5. 保留的 e2ee.py 引用(非 E2EE 加解密)
|
|
112
|
+
|
|
113
|
+
- `from .e2ee import ProtectedHeaders` — 纯数据类,V2 也用
|
|
114
|
+
- `from .e2ee import compute_state_hash` (2处) — 群组 state hash 验证工具函数
|
|
115
|
+
|
|
116
|
+
## 二、测试改动(`python/tests/`)
|
|
117
|
+
|
|
118
|
+
### 删除的测试文件(纯 V1 E2EE)
|
|
119
|
+
|
|
120
|
+
- `e2e_test_epoch_key_server.py` — V1 epoch key 服务端托管
|
|
121
|
+
- `integration_test_e2ee.py` — V1 P2P E2EE 集成
|
|
122
|
+
- `integration_test_multi_device_e2ee.py` — V1 多设备 E2EE
|
|
123
|
+
- `unit/test_client_group_e2ee.py` — V1 群组 E2EE 单元测试(93 个用例)
|
|
124
|
+
|
|
125
|
+
### 删除的测试用例(从现有文件中移除)
|
|
126
|
+
|
|
127
|
+
- `test_client.py`:24 个 V1 测试(prekey、send_encrypted V1、decrypt_group 等)
|
|
128
|
+
- `test_py_issues.py`:`TestPY004PrekeyRefreshLoop`
|
|
129
|
+
- `test_py_issues_batch2.py`:`TestPY001DecryptFailStillAutoAck`、`TestPY002KeyRecoveryRetry`、`TestPY003DissolveCleanup`、`TestPY005RotateLoopLeaderElection`
|
|
130
|
+
- `test_py_issues_batch3.py`:`TestPY002PushedSeqsLimit`、`TestPY005EpochWait`
|
|
131
|
+
|
|
132
|
+
### 修改的测试
|
|
133
|
+
|
|
134
|
+
- `test_client.py`:`test_e2ee_property` 改为断言 `e2ee` 属性不存在
|
|
135
|
+
- `integration_test_storage.py`:自定义 redirect handler 支持 PUT 302 重定向
|
|
136
|
+
|
|
137
|
+
## 三、服务端改动(`extensions/services/`)
|
|
138
|
+
|
|
139
|
+
| 文件 | 改动 |
|
|
140
|
+
|------|------|
|
|
141
|
+
| `gateway/entry.py` | kernel event 订阅补全 V2 事件(fallback);`_handle_event_notification` 路由补全 V2 事件 |
|
|
142
|
+
| `gateway/ws_server.py` | `_dispatch_event_from_service` 白名单补全 `group.state_committed` |
|
|
143
|
+
| `gateway/relay.py` | `_should_forward_event` 补全 `group.state_committed`;`_V2_ONLY_GROUP_METHODS` 补全 `propose_state/confirm_state/get_proposal` |
|
|
144
|
+
| `message/entry.py` | `AUN_DIRECT_EVENT_MESSAGE` 默认改为 True;V2 send 返回 status 对齐 V1 语义(`delivered`/`sent`) |
|
|
145
|
+
| `group/entry.py` | `AUN_DIRECT_EVENT_GROUP` 默认改为 True;`_targets_for_group_event` / `is_client_event` 补全 `group.state_committed`;`_rpc_v2_pull` / `_rpc_v2_ack` 补全成员权限检查 |
|
|
146
|
+
|
|
147
|
+
## 四、Bug 修复(需要其它 SDK 对齐)
|
|
148
|
+
|
|
149
|
+
### BUG-1: gap fill 时 contiguous_seq 卡死
|
|
150
|
+
|
|
151
|
+
**根因:** `on_pull_result` 从 `contiguous_seq` 开始 pull,如果服务端返回的消息跳过了某些 seq(永久空洞:竞态跳跃/未持久化/过期清理),`_try_advance` 逐个检查时会卡在第一个缺失的 seq 上,永远无法推进。新消息被阻塞在 SDK 内部有序队列中,上层收不到。
|
|
152
|
+
|
|
153
|
+
**修复:** `on_pull_result` 新增 `after_seq` 参数。当 `after_seq == contiguous_seq`(gap fill 场景)时,直接把 pull 到的最大 seq 作为新的 `contiguous_seq`。
|
|
154
|
+
|
|
155
|
+
**影响范围:** P2P pull、group pull、event pull 三条路径。
|
|
156
|
+
|
|
157
|
+
### BUG-2: V2 group pull 返回值去重导致手动 pull 拿不到已 push 的消息
|
|
158
|
+
|
|
159
|
+
**根因:** `_pull_group_v2_internal` 中 `_is_published_seq` 去重导致已通过 push 自动 pull 消费的消息在手动 pull 时被跳过,返回空列表。
|
|
160
|
+
|
|
161
|
+
**修复:** pull 返回值不再做 `_is_published_seq` 去重。`_publish_ordered_message` 内部仍做事件投递去重(防止重复触发应用层回调),但 pull 的返回值始终包含所有解密成功的消息。
|
|
162
|
+
|
|
163
|
+
### BUG-3: V2 message.send 返回 status 不对齐 V1 语义
|
|
164
|
+
|
|
165
|
+
**根因:** V2 send 返回 `"status": "accepted"`,但 SDK 和应用层已按 V1 语义(`sent`/`delivered`)实现。
|
|
166
|
+
|
|
167
|
+
**修复:** 服务端 `delivered_count > 0` 时返回 `delivered`,否则返回 `sent`。
|
|
168
|
+
|
|
169
|
+
### BUG-4: V2 解密元数据缺少 encryption_mode
|
|
170
|
+
|
|
171
|
+
**根因:** V2 解密后 `e2ee` 字段只有 `version` + `suite`,缺少 `encryption_mode` 和 `forward_secrecy`,导致依赖这些字段的测试/应用层判断失败。
|
|
172
|
+
|
|
173
|
+
**修复:** 补全 `encryption_mode: "v2_{suite}"` 和 `forward_secrecy: True`。
|
|
174
|
+
|
|
175
|
+
## 五、验证结果
|
|
176
|
+
|
|
177
|
+
| 测试 | 结果 |
|
|
178
|
+
|------|------|
|
|
179
|
+
| 单元测试 | 501 passed |
|
|
180
|
+
| V2 P2P E2EE | 12/12 |
|
|
181
|
+
| V2 Group E2EE | 8/8 |
|
|
182
|
+
| V2 Multi-device | 6/6 |
|
|
183
|
+
| Echo | 5/5 |
|
|
184
|
+
| Message Ack | 4/4 |
|
|
185
|
+
| Storage | 4/4 |
|
|
186
|
+
| 双域明文 | PASS |
|
|
187
|
+
| 双域加密 | PASS |
|
|
188
|
+
| 双域离线 | PASS |
|
|
189
|
+
| 双域群组 | 2/2 |
|
|
@@ -118,6 +118,7 @@ AID 由 `AIDStore.load()` 返回,应用层不直接构造。
|
|
|
118
118
|
| `verify_ssl` | `verifySsl` | `VerifySSL` | 是否校验 TLS 证书 |
|
|
119
119
|
| `root_ca_path` | `rootCaPath` | `RootCaPath` | 自定义根证书路径 |
|
|
120
120
|
| `debug` | `debug` | `Debug` | 是否开启调试日志 |
|
|
121
|
+
| `private_key_pem` | `privateKeyPem` | `PrivateKeyPem` | 明文私钥 PEM(由 `AIDStore.load()` 注入,空字符串表示无私钥)|
|
|
121
122
|
|
|
122
123
|
### 方法
|
|
123
124
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`message.send.params.payload`、`message.thought.put.params.payload`、`group.send.params.payload` 和 `group.thought.put.params.payload` 使用同一套业务负载约定。`payload` 是应用层 JSON 对象,服务端只做大小、JSON 可序列化、信封/封装类型和加密相关的必要检查;业务字段由发送端和接收端协商,服务端不按本文字段做强制校验。
|
|
4
4
|
|
|
5
|
-
示例展示的是 `payload` 片段:P2P 完整请求仍需要在同级传入 `to`;群消息完整请求仍需要在同级传入 `group_id`;思考内容需要在顶层通过 `context.type + context.id` 指定 selector。文本、图片、文件、思考内容等业务消息类型只能放在 `payload.type`;`message.send.params.type` / `message.thought.put.params.type` / `group.send.params.type` / `group.thought.put.params.type` 是信封或封装类型,例如 SDK 加密发送时自动填充的 `e2ee.encrypted` / `e2ee.group_encrypted`。
|
|
5
|
+
示例展示的是 `payload` 片段:P2P 完整请求仍需要在同级传入 `to`;群消息完整请求仍需要在同级传入 `group_id`;思考内容需要在顶层通过 `context.type + context.id` 指定 selector。文本、图片、文件、思考内容等业务消息类型只能放在 `payload.type`;`message.send.params.type` / `message.thought.put.params.type` / `group.send.params.type` / `group.thought.put.params.type` 是信封或封装类型,例如 SDK 加密发送时自动填充的 `e2ee.encrypted` / `e2ee.group_encrypted`。
|
|
6
6
|
|
|
7
7
|
## 类型总览
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|----------|------|----------|
|
|
11
11
|
| `text` | 纯文本或 Markdown 文本 | 普通对话、任务说明、通知正文 |
|
|
12
12
|
| `quote` | 带引用摘要的回复 | 回复某条消息、保留上下文 |
|
|
13
|
-
| `thought` | 思考过程片段 | Agent 针对某个 P2P 或群上下文的非广播思考内容 |
|
|
13
|
+
| `thought` | 思考过程片段 | Agent 针对某个 P2P 或群上下文的非广播思考内容 |
|
|
14
14
|
| `voice` | 语音文件引用及转写信息 | 语音消息、语音备忘 |
|
|
15
15
|
| `image` | 图片对象引用及展示信息 | 截图、流程图、图片分享 |
|
|
16
16
|
| `video` | 视频对象引用及封面信息 | 录屏、演示视频 |
|
|
@@ -38,19 +38,19 @@
|
|
|
38
38
|
| 字段 | 所在位置 | 说明 |
|
|
39
39
|
|------|----------|------|
|
|
40
40
|
| `to` | `message.send.params` | P2P 接收方 AID |
|
|
41
|
-
| `group_id` | `group.send.params` 和群消息信封 | 群组 ID |
|
|
42
|
-
| `context.type + context.id` | `message.thought.put/get.params` 和 `group.thought.put/get.params` | 思考内容 selector;必填,不要只放在 payload 内 |
|
|
43
|
-
| `protected_headers` / `headers` | `message.send` / `message.thought.put` / `group.send` / `group.thought.put` 参数 | E2EE 信封元数据,类似 HTTP headers;SDK 验 `_auth` 后在 `e2ee.protected_headers` 暴露 |
|
|
44
|
-
| `from` / `sender_aid` | 服务端生成的消息信封 | 发送方身份 |
|
|
41
|
+
| `group_id` | `group.send.params` 和群消息信封 | 群组 ID |
|
|
42
|
+
| `context.type + context.id` | `message.thought.put/get.params` 和 `group.thought.put/get.params` | 思考内容 selector;必填,不要只放在 payload 内 |
|
|
43
|
+
| `protected_headers` / `headers` | `message.send` / `message.thought.put` / `group.send` / `group.thought.put` 参数 | E2EE 信封元数据,类似 HTTP headers;SDK 验 `_auth` 后在 `e2ee.protected_headers` 暴露 |
|
|
44
|
+
| `from` / `sender_aid` | 服务端生成的消息信封 | 发送方身份 |
|
|
45
45
|
| `message_id` / `seq` / `timestamp` / `created_at` | 服务端生成或发送参数 | 当前消息 ID、序号和服务端时间 |
|
|
46
46
|
| `encrypted` / `delivery_mode` | 发送参数或连接上下文 | 加密和 P2P 投递语义 |
|
|
47
47
|
| `dispatch_mode` | 群消息信封和 SDK 注入的群消息 payload | 群消息应用层分发模式标签:`broadcast` / `mention`;由群设置决定,不作为 `group.send` 单次入参 |
|
|
48
48
|
| `type` / `message_type` | 发送参数或消息信封 | 信封/封装类型,如 `e2ee.encrypted` / `e2ee.group_encrypted` |
|
|
49
|
-
| `dispatch` / `duty_state` / `message_dispatch` | `group.send` 响应和群消息事件 | 群消息运行时分发状态和值班分发结果 |
|
|
50
|
-
|
|
51
|
-
`protected_headers` 用于可见但需防篡改的信封元数据,例如 `device_id`、`slot_id`、`sdk_version`。它不属于业务 payload,也不提供机密性;需要端到端保密的上下文仍应放在 `payload.client_context` 或其他 payload 字段内。
|
|
52
|
-
|
|
53
|
-
## 公共辅助字段
|
|
49
|
+
| `dispatch` / `duty_state` / `message_dispatch` | `group.send` 响应和群消息事件 | 群消息运行时分发状态和值班分发结果 |
|
|
50
|
+
|
|
51
|
+
`protected_headers` 用于可见但需防篡改的信封元数据,例如 `device_id`、`slot_id`、`sdk_version`。它不属于业务 payload,也不提供机密性;需要端到端保密的上下文仍应放在 `payload.client_context` 或其他 payload 字段内。
|
|
52
|
+
|
|
53
|
+
## 公共辅助字段
|
|
54
54
|
|
|
55
55
|
以下字段可出现在多数 payload 中;如无需要,不必携带。
|
|
56
56
|
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
|
|
129
129
|
### `thought`:思考内容
|
|
130
130
|
|
|
131
|
-
`thought` 用于 Agent 暴露针对某个 P2P 或群上下文的思考过程片段。它只应通过 `message.thought.put` 或 `group.thought.put` 发送,不作为普通 `message.send` / `group.send` 消息广播;有兴趣的客户端通过对应的 `*.thought.get` 主动读取。
|
|
131
|
+
`thought` 用于 Agent 暴露针对某个 P2P 或群上下文的思考过程片段。它只应通过 `message.thought.put` 或 `group.thought.put` 发送,不作为普通 `message.send` / `group.send` 消息广播;有兴趣的客户端通过对应的 `*.thought.get` 主动读取。
|
|
132
132
|
|
|
133
133
|
| 字段 | 类型 | 必填 | 说明 |
|
|
134
134
|
|------|------|:----:|------|
|
|
@@ -146,7 +146,7 @@
|
|
|
146
146
|
}
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
`message.thought.put` / `group.thought.put` 的顶层 selector 用于定位 thought head,只使用 `context.type + context.id`。`payload` 内如需展示引用摘要,可另行携带 `quote` 或 `client_context`,但不能替代顶层 selector。
|
|
149
|
+
`message.thought.put` / `group.thought.put` 的顶层 selector 用于定位 thought head,只使用 `context.type + context.id`。`payload` 内如需展示引用摘要,可另行携带 `quote` 或 `client_context`,但不能替代顶层 selector。
|
|
150
150
|
|
|
151
151
|
### `voice`:语音消息
|
|
152
152
|
|