@agentunion/fastaun-browser 0.3.3 → 0.3.5

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 (67) hide show
  1. package/CHANGELOG.md +113 -85
  2. package/_packed_docs/CHANGELOG.md +113 -85
  3. package/_packed_docs/INDEX.md +81 -0
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +55 -0
  5. 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 +328 -0
  6. package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +686 -0
  7. 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 -0
  8. 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 -0
  9. 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 -0
  10. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +5 -5
  11. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +1 -1
  12. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +2 -2
  13. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +46 -6
  14. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +89 -12
  15. package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +19 -1
  16. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +20 -5
  17. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +8 -8
  18. 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 -0
  19. package/_packed_docs/sdk/INDEX.md +22 -22
  20. package/_packed_docs/sdk/README.md +3 -3
  21. package/dist/auth.d.ts +10 -11
  22. package/dist/auth.d.ts.map +1 -1
  23. package/dist/auth.js +127 -91
  24. package/dist/auth.js.map +1 -1
  25. package/dist/bundle.js +649 -274
  26. package/dist/client.d.ts +19 -10
  27. package/dist/client.d.ts.map +1 -1
  28. package/dist/client.js +238 -111
  29. package/dist/client.js.map +1 -1
  30. package/dist/errors.d.ts +4 -0
  31. package/dist/errors.d.ts.map +1 -1
  32. package/dist/errors.js +7 -0
  33. package/dist/errors.js.map +1 -1
  34. package/dist/index.d.ts +3 -3
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -3
  37. package/dist/index.js.map +1 -1
  38. package/dist/keystore/index.d.ts +5 -0
  39. package/dist/keystore/index.d.ts.map +1 -1
  40. package/dist/keystore/indexeddb.d.ts +12 -0
  41. package/dist/keystore/indexeddb.d.ts.map +1 -1
  42. package/dist/keystore/indexeddb.js +64 -6
  43. package/dist/keystore/indexeddb.js.map +1 -1
  44. package/dist/namespaces/auth.d.ts +9 -3
  45. package/dist/namespaces/auth.d.ts.map +1 -1
  46. package/dist/namespaces/auth.js +64 -20
  47. package/dist/namespaces/auth.js.map +1 -1
  48. package/dist/secret-store/indexeddb-store.js +1 -1
  49. package/dist/secret-store/indexeddb-store.js.map +1 -1
  50. package/dist/transport.d.ts +9 -1
  51. package/dist/transport.d.ts.map +1 -1
  52. package/dist/transport.js +158 -64
  53. package/dist/transport.js.map +1 -1
  54. package/dist/v2/e2ee/decrypt.js +1 -1
  55. package/dist/v2/e2ee/decrypt.js.map +1 -1
  56. package/dist/v2/e2ee/encrypt-p2p.d.ts.map +1 -1
  57. package/dist/v2/e2ee/encrypt-p2p.js +3 -2
  58. package/dist/v2/e2ee/encrypt-p2p.js.map +1 -1
  59. package/dist/v2/session/session.d.ts +1 -0
  60. package/dist/v2/session/session.d.ts.map +1 -1
  61. package/dist/v2/session/session.js +7 -1
  62. package/dist/v2/session/session.js.map +1 -1
  63. package/package.json +43 -43
  64. package/dist/e2ee-group.d.ts +0 -276
  65. package/dist/e2ee-group.d.ts.map +0 -1
  66. package/dist/e2ee-group.js +0 -1653
  67. package/dist/e2ee-group.js.map +0 -1
@@ -0,0 +1,257 @@
1
+ # 附录 N — 分布式 Trace 协议
2
+
3
+ ## 设计目标
4
+
5
+ 为 AUN RPC 调用链路(SDK → Gateway → Service → Gateway → SDK)提供轻量级的分布式追踪能力,
6
+ 支持两种使用场景:
7
+
8
+ 1. **日志关联(log 模式)** — 全链路日志通过 `trace_id` 串联,零开销,可在生产环境常开
9
+ 2. **诊断回传(diag 模式)** — 各环节追加 span,response 携带完整链路返回调用者,
10
+ 仅用于疑难问题诊断,需通过开关启用
11
+
12
+ 不依赖 OpenTelemetry / Jaeger 等外部体系,自定义 `_trace` 字段即可,跨语言实现成本极低。
13
+
14
+ ---
15
+
16
+ ## 一、协议层
17
+
18
+ ### 1.1 字段位置
19
+
20
+ `_trace` 字段位于 JSON-RPC `params` 内,沿用 AUN 现有框架字段约定(与 `_caller_id`、`_auth` 同级):
21
+
22
+ ```json
23
+ {
24
+ "jsonrpc": "2.0",
25
+ "id": 1,
26
+ "method": "message.send",
27
+ "params": {
28
+ "to": "bob.aid.com",
29
+ "body": "hello",
30
+ "_trace": {
31
+ "trace_id": "a1b2c3d4e5f6...",
32
+ "mode": "log"
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ ### 1.2 字段定义
39
+
40
+ | 字段 | 类型 | 必填 | 说明 |
41
+ |------|------|------|------|
42
+ | `trace_id` | string | 是 | 32 hex chars(16 bytes 随机),由 SDK 生成,全链路唯一 |
43
+ | `mode` | string | 是 | `"log"` 或 `"diag"`,缺失视为 `"log"` |
44
+ | `spans` | array | 否 | 仅 `diag` 模式存在,各环节追加 |
45
+
46
+ **说明**:`mode: "off"` 不需要显式表示——不带 `_trace` 字段即为 off 状态。
47
+
48
+ ### 1.3 Span 结构
49
+
50
+ ```json
51
+ {
52
+ "node": "gateway",
53
+ "ts": 1716300000156,
54
+ "action": "relay_in",
55
+ "ms": 0,
56
+ "detail": "route→message"
57
+ }
58
+ ```
59
+
60
+ | 字段 | 类型 | 说明 |
61
+ |------|------|------|
62
+ | `node` | string | 环节标识:`sdk-{aid}`、`gateway`、`{service_name}` |
63
+ | `ts` | number | Unix 毫秒时间戳(入站时刻) |
64
+ | `action` | string | 动作:`send` / `relay_in` / `process` / `relay_out` / `deliver` |
65
+ | `ms` | number | 本环节处理耗时(出站时填写,入站初始为 0) |
66
+ | `detail` | string | 可选,关键上下文(路由目标、错误码等),最多 256 字符 |
67
+
68
+ ---
69
+
70
+ ## 二、链路传播流程
71
+
72
+ ```
73
+ SDK-A Gateway Service Gateway SDK-B
74
+ │ │ │ │ │
75
+ │─── params._trace ─▶│ │ │ │
76
+ │ {trace_id, mode, │ │ │ │
77
+ │ spans:[sdk-send]}│ │ │ │
78
+ │ │── 追加 gateway ───▶│ │ │
79
+ │ │ 转发到 service │ │ │
80
+ │ │ │── 追加 svc span ──▶│ │
81
+ │ │ │ 返回 response │ │
82
+ │ │◀── response ───────│ │ │
83
+ │ │ 追加 gateway-out │ │ │
84
+ │◀── response._trace─│ │ │ │
85
+ │ │ │ │ │
86
+ │ │─── event._trace ──────────────────────▶│── deliver ────────▶│
87
+ ```
88
+
89
+ ### 2.1 各环节职责
90
+
91
+ | 环节 | 入站行为 | 出站行为 |
92
+ |------|----------|----------|
93
+ | SDK 发起 | 生成 trace_id;mode≠off 时构造 `_trace` 注入 params | — |
94
+ | Gateway 入站 | 读取 _trace,应用降级;diag 模式追加 `relay_in` span | — |
95
+ | Service 处理 | 读取 _trace 写入日志(log)或追加 span(diag) | response 透传 _trace |
96
+ | Gateway 出站 | diag 模式追加 `relay_out` span | log 模式剥离 _trace;diag 模式注入 response 顶层 |
97
+ | SDK 接收 | 提取 response._trace 回调 trace observer | — |
98
+
99
+ ---
100
+
101
+ ## 三、Response 回传(仅 diag 模式)
102
+
103
+ Gateway 在 `deliver_response_to_client` 中将 `_trace` 注入 response 顶层(与 `_meta` 平级):
104
+
105
+ ```json
106
+ {
107
+ "jsonrpc": "2.0",
108
+ "id": 1,
109
+ "result": {"status": "ok", "message_id": "..."},
110
+ "_meta": {"agent_md_etag": "..."},
111
+ "_trace": {
112
+ "trace_id": "a1b2c3...",
113
+ "mode": "diag",
114
+ "spans": [
115
+ {"node": "sdk-alice.aid.com", "ts": 1716300000100, "action": "send"},
116
+ {"node": "gateway", "ts": 1716300000123, "action": "relay_in", "ms": 2, "detail": "→message"},
117
+ {"node": "message", "ts": 1716300000125, "action": "process", "ms": 15},
118
+ {"node": "gateway", "ts": 1716300000142, "action": "relay_out", "ms": 1}
119
+ ]
120
+ }
121
+ }
122
+ ```
123
+
124
+ **注意**:log 模式下 response 不带 `_trace`(保持 envelope 干净,零开销)。
125
+
126
+ ---
127
+
128
+ ## 四、开关层级
129
+
130
+ ### 4.1 三态定义
131
+
132
+ | 值 | 行为 |
133
+ |---|---|
134
+ | `off` | 不生成 `_trace`,零开销(默认) |
135
+ | `log` | 生成 trace_id + 各环节写本地日志,response 不回传 |
136
+ | `diag` | 同 log + spans 追加 + response 回传完整链路 |
137
+
138
+ ### 4.2 控制点
139
+
140
+ | 层级 | 配置位置 | 默认值 | 作用 |
141
+ |------|----------|--------|------|
142
+ | 服务端上限 | Gateway 环境变量 `AUN_TRACE_MAX_MODE` | `"log"` | 超过此级别自动降级 |
143
+ | SDK 会话级 | `client.set_trace_mode("log")` | `"off"` | 连接内所有请求默认 mode |
144
+ | SDK 调用级 | `client.rpc("method", params, trace="diag")` | 继承会话级 | 单次覆盖,优先级最高 |
145
+
146
+ ### 4.3 优先级规则
147
+
148
+ ```
149
+ 最终 mode = min(SDK 调用级 || SDK 会话级, 服务端上限)
150
+ 其中 off < log < diag
151
+ ```
152
+
153
+ ### 4.4 服务端降级逻辑(Gateway 入站时)
154
+
155
+ ```python
156
+ client_mode = trace.get("mode", "off")
157
+ server_max = config.trace_max_mode # "off" | "log" | "diag"
158
+ effective = min(client_mode, server_max)
159
+ if effective != client_mode:
160
+ trace["mode"] = effective
161
+ if effective != "diag":
162
+ trace.pop("spans", None) # 降级到 log/off 时丢弃已有 spans
163
+ ```
164
+
165
+ **生产环境推荐配置**:`AUN_TRACE_MAX_MODE=log`,diag 需运维手动开启。
166
+
167
+ ---
168
+
169
+ ## 五、各组件改动点
170
+
171
+ ### 5.1 SDK 侧
172
+
173
+ **`transport.py`**:
174
+ - `call()` 方法:会话/调用级 mode 非 off 时,构造 `_trace` 注入 params
175
+ - response 处理:提取 `_trace` 回调 trace observer(与现有 `_meta_observer` 模式一致)
176
+
177
+ **`client.py`**:
178
+ - 新增 `set_trace_mode(mode: str)`:设置会话级默认 mode
179
+ - `rpc()` 方法新增 `trace` 参数:单次覆盖 mode
180
+ - 暴露 `set_trace_observer(callback)`:接收 diag 模式回传的 spans
181
+
182
+ ### 5.2 Gateway 侧
183
+
184
+ **`ws_server.py`**:
185
+ - `_resolve_ws_message_trace()` 改造:读取 mode,应用服务端降级
186
+ - 入站时追加 `relay_in` span(diag 模式)
187
+ - `_strip_internal_route()` 保持现状:log 模式仍剥离 `_trace`,diag 模式由 response 路径专门处理
188
+
189
+ **`relay.py`**:
190
+ - `deliver_response_to_client()`:diag 模式追加 `relay_out` span,将 `_trace` 注入 response 顶层
191
+
192
+ ### 5.3 Service 侧
193
+
194
+ 通用 pattern(适用于 message / group / storage / stream / mail 等所有服务):
195
+ 1. RPC 入口提取 `params._trace`
196
+ 2. 处理过程中通过 trace_id 写入日志
197
+ 3. diag 模式追加自身 span
198
+ 4. response 透传 `_trace` 字段
199
+
200
+ ---
201
+
202
+ ## 六、日志格式(log 模式)
203
+
204
+ 各环节按现有日志规范输出,前缀加 trace_id:
205
+
206
+ ```
207
+ [2026-05-21 10:00:00.123][INFO][gateway] [trace=a1b2c3d4] relay_in method=message.send conn=42
208
+ [2026-05-21 10:00:00.125][INFO][message] [trace=a1b2c3d4] process persist=true target=bob.aid.com
209
+ [2026-05-21 10:00:00.140][INFO][gateway] [trace=a1b2c3d4] relay_out duration_ms=17
210
+ ```
211
+
212
+ 排查时 `grep trace=a1b2c3d4` 即可串联全链路。
213
+
214
+ ---
215
+
216
+ ## 七、安全约束
217
+
218
+ | 约束 | 限制 |
219
+ |------|------|
220
+ | spans 数组最大长度 | 32 条,超出由 Gateway 截断尾部 |
221
+ | 单个 detail 最大长度 | 256 字符 |
222
+ | trace_id 长度 | 严格 32 hex chars,不合规由 Gateway 重新生成 |
223
+ | 敏感信息 | spans 禁止包含消息体、密钥、Token 等,只记录路由/耗时/错误码等元数据 |
224
+ | 生产环境默认 | `AUN_TRACE_MAX_MODE=log`,diag 需运维手动开启 |
225
+ | 跨域传播 | 跨 federation 边界时保留 trace_id,spans 在边界节点视为新链路起点 |
226
+
227
+ ---
228
+
229
+ ## 八、跨语言实现要点
230
+
231
+ 所有 SDK(Python / Go / TypeScript / JavaScript / C++)需保持一致:
232
+
233
+ 1. **trace_id 生成**:16 字节加密随机数,hex 编码
234
+ 2. **时间戳**:Unix 毫秒(不使用秒/纳秒),统一单位
235
+ 3. **字段顺序**:JSON 字段顺序不影响语义,但建议按 `trace_id, mode, spans` 顺序输出便于阅读
236
+ 4. **observer 接口**:各 SDK 提供 `set_trace_observer(callback)` 接口,签名一致
237
+ 5. **会话/调用级 API 命名**:
238
+ - 设置:`set_trace_mode(mode)` / `setTraceMode(mode)`
239
+ - 单次覆盖:`rpc(method, params, trace=mode)` / `rpc(method, params, {trace: mode})`
240
+
241
+ ---
242
+
243
+ ## 九、未实现 / 后续扩展
244
+
245
+ 以下能力本附录暂不覆盖,留作后续扩展:
246
+
247
+ - **采样率控制**:当前 SDK 完全控制 mode,未引入概率采样(如 1% diag)
248
+ - **OpenTelemetry 适配**:未来如需对接 Jaeger / Zipkin,可在 Gateway 端增加导出适配层,
249
+ 将 spans 转为 OTLP 格式
250
+ - **跨域链路连续性**:当前跨 federation 边界视为新链路,未实现端到端 trace_id 透传
251
+ - **span 父子关系**:当前 spans 数组仅按时间排序,未引入 parent_span_id(保持极简)
252
+
253
+ ---
254
+
255
+ ## 文档版本
256
+
257
+ - v1.0 — 2026-05-21 初稿,定义协议字段、链路传播、开关层级、安全约束
@@ -30,17 +30,17 @@ BOB = f"bob{random.randint(1000,9999)}.{DOMAIN}"
30
30
 
31
31
 
32
32
  async def create_client(aid: str) -> tuple[AUNClient, dict]:
33
- """创建客户端 → 加载或创建 AID → 认证 → 返回 (client, auth)"""
33
+ """创建客户端 → 注册 AID → 认证 → 返回 (client, auth)"""
34
34
  client = AUNClient() # 默认 aun_path: ~/.aun
35
35
 
36
36
  # 先检查本地是否已有该 AID 的身份
37
37
  known = any(item["aid"] == aid for item in client.list_identities())
38
38
  if not known:
39
- # 不存在则创建
39
+ # 不存在则注册
40
40
  try:
41
- await client.auth.create_aid({"aid": aid})
41
+ await client.auth.register_aid({"aid": aid})
42
42
  except AuthError as e:
43
- print(f"[错误] 创建 AID 失败 ({aid}): {e}")
43
+ print(f"[错误] 注册 AID 失败 ({aid}): {e}")
44
44
  raise
45
45
  except ConnectionError as e:
46
46
  print(f"[错误] 网络连接失败: {e}")
@@ -213,7 +213,7 @@ await client.connect(auth, {
213
213
  完整的使用流程见上方"最小示例",核心步骤:
214
214
 
215
215
  1. **创建客户端** - `AUNClient(config)`
216
- 2. **加载或创建 AID** - `load_identity_or_none()` → `create_aid()`
216
+ 2. **注册 AID** - `check_aid()` → `register_aid()`
217
217
  3. **认证** - `authenticate()` 获取令牌
218
218
  4. **订阅事件** - `on("message.received", handler)`
219
219
  5. **连接** - `connect(auth, options)`
@@ -210,7 +210,7 @@ async def authenticate(aid: str) -> dict:
210
210
  try:
211
211
  client = AUNClient({"aun_path": f"~/.aun/{aid}"})
212
212
  if not client._auth.load_identity_or_none(aid):
213
- await client.auth.create_aid({"aid": aid})
213
+ await client.auth.register_aid({"aid": aid})
214
214
  auth = await client.auth.authenticate({"aid": aid})
215
215
  return auth
216
216
  except AuthError as e:
@@ -19,8 +19,8 @@ AID 是 Agent 的全局唯一身份,格式为域名形式:`alice.agentid.pub
19
19
  import random
20
20
  MY_AID = f"alice-{random.randint(1000,9999)}.agentid.pub"
21
21
 
22
- # 创建(仅首次)
23
- await client.auth.create_aid({"aid": MY_AID})
22
+ # 注册(仅首次)
23
+ await client.auth.register_aid({"aid": MY_AID})
24
24
 
25
25
  # 认证
26
26
  auth = await client.auth.authenticate({"aid": MY_AID})
@@ -2,7 +2,47 @@
2
2
 
3
3
  ---
4
4
 
5
- ## 创建 AID 和认证
5
+ ## v0.3.4 行为变更
6
+
7
+ ### 注册与认证分离
8
+
9
+ v0.3.4 起,`authenticate()` **不再隐式注册**。如果本地无完整身份(缺 keypair 或 cert),`authenticate()` 直接抛 `StateError`。
10
+
11
+ 正确流程:
12
+
13
+ ```python
14
+ await client.auth.register_aid({"aid": aid}) # 1. 注册(生成密钥对 + 获取证书)
15
+ auth = await client.auth.authenticate({"aid": aid}) # 2. 认证(获取 token)
16
+ await client.connect(auth, {}) # 3. 连接
17
+ ```
18
+
19
+ **半成品恢复**:如果本地有 keypair 但无 cert(上次注册中断),`register_aid()` 会自动向服务端查询并恢复证书,无需手动清理。
20
+
21
+ ### 身份查询 API
22
+
23
+ v0.3.4 新增两个只读 API,用于检查本地身份状态(无网络请求、无副作用):
24
+
25
+ ```python
26
+ # 加载身份(不存在时抛 StateError)
27
+ identity = client.auth.load_identity({"aid": aid})
28
+
29
+ # 加载身份(不存在时返回 None)
30
+ identity = client.auth.load_identity_or_none({"aid": aid})
31
+
32
+ # 获取对端证书 PEM(本地缓存优先,未命中走 PKI)
33
+ cert_pem = await client.auth.fetch_peer_cert({"aid": peer_aid})
34
+ ```
35
+
36
+ ### 迁移说明
37
+
38
+ | 旧 API(v0.3.3-) | 新 API(v0.3.4+) |
39
+ |---|---|
40
+ | `create_aid()` | `register_aid()`(已移除 `create_aid`) |
41
+ | `authenticate()` 自动注册 | 必须先显式调用 `register_aid()` |
42
+
43
+ ---
44
+
45
+ ## 注册 AID 和认证
6
46
 
7
47
  ```python
8
48
  from aun_core import AUNClient
@@ -10,12 +50,12 @@ from aun_core import AUNClient
10
50
  async def setup(aid: str):
11
51
  client = AUNClient() # 默认 aun_path: ~/.aun
12
52
 
13
- # 创建 AID
53
+ # 注册 AID
14
54
  try:
15
- result = await client.auth.create_aid({"aid": aid})
55
+ result = await client.auth.register_aid({"aid": aid})
16
56
  # result: {"aid": ..., "cert_pem": ..., "gateway": ...}
17
57
  except Exception as e:
18
- print(f"创建 AID 失败: {e}")
58
+ print(f"注册 AID 失败: {e}")
19
59
  raise
20
60
 
21
61
  auth = await client.auth.authenticate({"aid": aid})
@@ -159,7 +199,7 @@ print(client.aid) # "alice.agentid.pub"
159
199
 
160
200
  ## 网关自动发现
161
201
 
162
- `create_aid()` / `authenticate()` 内部会自动发现 Gateway。
202
+ `register_aid()` / `authenticate()` 内部会自动发现 Gateway。
163
203
 
164
204
  - 生产配置(`verify_ssl=true`)下,优先尝试 `https://{aid}/.well-known/aun-gateway`
165
205
  - 若失败,则回退到 `https://gateway.{issuer}/.well-known/aun-gateway`
@@ -204,7 +244,7 @@ Name Service 同时提供面向 Agent Web 的标准 HTTP 资源:
204
244
 
205
245
  ### 推荐主 API(自 v0.x 起)
206
246
 
207
- SDK 在 `AUNClient` 上提供三个一站式主方法,分别封装"发布"、"下载"、"一致性检查"三条主线。文件统一存放在 `{aun_path}/AgentMDs/{aid}/agent.md`,由 SDK 管理;元数据持久化到 `agent_md_cache` 表 / `list.json`。
247
+ SDK 在 `AUNClient` 上提供三个一站式主方法,分别封装"发布"、"下载"、"一致性检查"三条主线。文件统一存放在 `{aun_path}/AgentMDs/{aid}/agent.md`,由 SDK 管理;元数据持久化到 `agent_md_cache` 表 / `agentmd.json`。
208
248
 
209
249
  ```python
210
250
  # 发布自己的 agent.md(读 SDK 管理的本地文件 → 签名 → 上传 → 刷新内部 etag)
@@ -23,9 +23,11 @@
23
23
  - [check_gateway_health()](#await-check_gateway_healthgateway_url-str-timeout-float--50---bool) - 检查网关可用性
24
24
 
25
25
  ### [AUNClient.Auth](#authnamespace-clientauth)
26
- - [create_aid()](#await-create_aidparams-dict---dict) - 注册新 AID
26
+ - [register_aid()](#await-register_aidparams-dict---dict) - 注册新 AID
27
27
  - [check_aid()](#await-check_aidparams-dict---dict) - 检查 AID 状态(本地完整性 + 远程注册)
28
28
  - [authenticate()](#await-authenticateparams-dict--none---dict) - 认证获取令牌
29
+ - [load_identity()](#load_identityparams-dict--none--none---dict) - 只读加载本地身份
30
+ - [fetch_peer_cert()](#await-fetch_peer_certparams-dict---str) - 获取对端证书
29
31
  - [sign_agent_md()](#await-sign_agent_mdcontent-str-aid-str--none---str) - 为 agent.md 生成尾部签名 **(已 deprecated,建议改用 `client.publish_agent_md`)**
30
32
  - [verify_agent_md()](#await-verify_agent_mdcontent-str-aid-str--none-cert_pem-str--none---dict) - 验证 agent.md 尾部签名 **(已 deprecated,建议改用 `client.fetch_agent_md`)**
31
33
  - [upload_agent_md()](#await-upload_agent_mdcontent-str---dict) - 上传自己的 agent.md **(已 deprecated,建议改用 `client.publish_agent_md`)**
@@ -405,7 +407,7 @@ for item in identities:
405
407
  - 传入非空路径:切换到指定目录
406
408
  - 传入空字符串或 `None`:恢复默认目录 `{aun_path}/AgentMDs`
407
409
  - 目录不存在时自动创建
408
- - 切换后清空内存中的 agent.md 缓存(下次操作会重新从磁盘/list.json 加载)
410
+ - 切换后清空内存中的 agent.md 缓存(下次操作会重新从磁盘/agentmd.json 加载)
409
411
 
410
412
  **API 跨语言对齐:**
411
413
 
@@ -423,11 +425,12 @@ for item in identities:
423
425
 
424
426
  ```
425
427
  {agent_md_path}/
426
- ├── list.json # 所有 AID 的元数据索引
427
428
  ├── {aid_1}/
428
- └── agent.md # aid_1 的 agent.md 正文
429
+ ├── agent.md # aid_1 的 agent.md 正文
430
+ │ └── agentmd.json # aid_1 的元数据(etag、时间戳等)
429
431
  ├── {aid_2}/
430
- └── agent.md
432
+ ├── agent.md
433
+ │ └── agentmd.json
431
434
  └── ...
432
435
  ```
433
436
 
@@ -448,7 +451,7 @@ client.set_agent_md_path() # 回到 {aun_path}/AgentMDs
448
451
 
449
452
  ### `await publish_agent_md() -> dict` — agent.md 发布主 API
450
453
 
451
- 读取 SDK 管理的本地 `agent.md`(路径:`{aun_path}/AgentMDs/{self_aid}/agent.md`)→ 调用 `auth.sign_agent_md` 在尾部追加 `<!-- AUN-SIGNATURE -->` 块 → 调用 `auth.upload_agent_md` 上传到服务端 → 以**上传字节的 sha256**计算 quoted etag 写入内部 `_local_agent_md_etag` 与持久化缓存(`agent_md_cache` 表 / `list.json`),使后续应用事件 payload 中的 `_agent_md.local_etag` 字段反映服务端实际生效的版本。
454
+ 读取 SDK 管理的本地 `agent.md`(路径:`{aun_path}/AgentMDs/{self_aid}/agent.md`)→ 调用 `auth.sign_agent_md` 在尾部追加 `<!-- AUN-SIGNATURE -->` 块 → 调用 `auth.upload_agent_md` 上传到服务端 → 以**上传字节的 sha256**计算 quoted etag 写入内部 `_local_agent_md_etag` 与持久化缓存(`agent_md_cache` 表 / `agentmd.json`),使后续应用事件 payload 中的 `_agent_md.local_etag` 字段反映服务端实际生效的版本。
452
455
 
453
456
  **API 跨语言对齐:**
454
457
 
@@ -484,7 +487,7 @@ print(result["agent_md_url"], result["etag"])
484
487
 
485
488
  ### `await fetch_agent_md(aid: str | None = None) -> dict` — agent.md 下载主 API
486
489
 
487
- 下载指定 AID 的 `agent.md`,自动调用 `auth.verify_agent_md` 验签;`aid` 缺省取本地身份;下载结果**固定保存**到 `{aun_path}/AgentMDs/{aid}/agent.md`,并同步更新持久化缓存(`agent_md_cache` 表 / `list.json`)。若目标 aid 是自己则刷新内部 `_local_agent_md_etag` 并计算 `in_sync`。
490
+ 下载指定 AID 的 `agent.md`,自动调用 `auth.verify_agent_md` 验签;`aid` 缺省取本地身份;下载结果**固定保存**到 `{aun_path}/AgentMDs/{aid}/agent.md`,并同步更新持久化缓存(`agent_md_cache` 表 / `agentmd.json`)。若目标 aid 是自己则刷新内部 `_local_agent_md_etag` 并计算 `in_sync`。
488
491
 
489
492
  **API 跨语言对齐:**
490
493
 
@@ -681,9 +684,9 @@ SDK 在 publish `message.received` / `group.message_created` 等应用事件时
681
684
 
682
685
  ---
683
686
 
684
- ### `await create_aid(params: dict) -> dict`
687
+ ### `await register_aid(params: dict) -> dict`
685
688
 
686
- 注册新 AID,本地生成 ECDSA 密钥对并向 Gateway 申请 X.509 证书。
689
+ 注册新 AID,本地生成 ECDSA 密钥对并向 Gateway 申请 X.509 证书。该方法严格执行注册语义:若 AID 已在本地存在或已在远程注册,将返回错误而非静默复用。调用前应先通过 `check_aid()` 确认 AID 可注册。
687
690
 
688
691
  **参数**
689
692
 
@@ -701,10 +704,21 @@ SDK 在 publish `message.received` / `group.message_created` 等应用事件时
701
704
 
702
705
  ```python
703
706
  MY_AID = f"alice-{random.randint(1000,9999)}.agentid.pub"
704
- result = await client.auth.create_aid({"aid": MY_AID})
707
+ result = await client.auth.register_aid({"aid": MY_AID})
705
708
  # {"aid": "alice-XXXX.agentid.pub", "cert_pem": "-----BEGIN...", "gateway": "ws://..."}
706
709
  ```
707
710
 
711
+ **跨语言**
712
+
713
+ | 语言 | 调用方式 |
714
+ |------|----------|
715
+ | Python | `await client.auth.register_aid({"aid": "..."})` |
716
+ | TypeScript | `await client.auth.registerAid({ aid: '...' })` |
717
+ | Go | `client.Auth.RegisterAID(ctx, map[string]any{"aid": "..."})` |
718
+ | JavaScript(浏览器) | `await client.auth.registerAid({ aid: '...' })` |
719
+
720
+ > 服务端 RPC 方法名为 `auth.create_aid`,SDK 对外暴露为 `register_aid` / `RegisterAID` / `registerAid` 以明确注册语义。
721
+
708
722
  ---
709
723
 
710
724
  ### `await check_aid(params: dict) -> dict`
@@ -732,8 +746,8 @@ if result["status"] == "local_ready":
732
746
  # 可以直接连接
733
747
  pass
734
748
  elif result["can_register"]:
735
- # AID 可用,创建新身份
736
- await client.auth.create_aid({"aid": "alice.agentid.pub"})
749
+ # AID 可用,注册新身份
750
+ await client.auth.register_aid({"aid": "alice.agentid.pub"})
737
751
  ```
738
752
 
739
753
  **跨语言**
@@ -773,6 +787,69 @@ auth = await client.auth.authenticate({"aid": MY_AID})
773
787
 
774
788
  ---
775
789
 
790
+ ### `load_identity(params: dict | None = None) -> dict`
791
+
792
+ 只读加载本地已注册身份(密钥对 + 证书 + 实例状态)。纯本地操作,无网络请求,无副作用。
793
+
794
+ **参数**
795
+
796
+ | 字段 | 类型 | 必填 | 说明 |
797
+ |------|------|------|------|
798
+ | `aid` | `str` | 否 | 指定 AID;不传则使用当前 AID |
799
+
800
+ **返回值**
801
+
802
+ | 字段 | 类型 | 说明 |
803
+ |------|------|------|
804
+ | `aid` | `str` | AID 标识 |
805
+ | `private_key_pem` | `str` | 私钥 PEM |
806
+ | `public_key_der_b64` | `str` | 公钥 DER Base64 |
807
+ | `cert` | `str` | 证书 PEM(如已签发) |
808
+ | `access_token` | `str` | 缓存的 access_token(如有) |
809
+
810
+ **异常**:本地无完整身份时抛 `StateError`。
811
+
812
+ ```python
813
+ identity = client.auth.load_identity({"aid": "alice.example.com"})
814
+ ```
815
+
816
+ **OrNone 变体**:`load_identity_or_none(params)` — 不存在时返回 `None` 而非抛异常。
817
+
818
+ | 语言 | 方法名 |
819
+ |------|--------|
820
+ | Python | `client.auth.load_identity()` / `client.auth.load_identity_or_none()` |
821
+ | TypeScript | `client.auth.loadIdentity()` / `client.auth.loadIdentityOrNull()` |
822
+ | JavaScript | `await client.auth.loadIdentity()` / `await client.auth.loadIdentityOrNull()` |
823
+ | Go | `client.Auth.LoadIdentity(aid)` / `client.Auth.LoadIdentityOrNil(aid)` |
824
+
825
+ ---
826
+
827
+ ### `await fetch_peer_cert(params: dict) -> str`
828
+
829
+ 获取对端 AID 的证书 PEM。优先走本地 `public/certs/` 缓存,未命中时通过 PKI HTTP 端点下载并做完整链验证后落缓存。
830
+
831
+ **参数**
832
+
833
+ | 字段 | 类型 | 必填 | 说明 |
834
+ |------|------|------|------|
835
+ | `aid` | `str` | 是 | 对端 AID |
836
+ | `cert_fingerprint` | `str` | 否 | 指定证书指纹(用于精确匹配特定版本) |
837
+
838
+ **返回值**:证书 PEM 字符串。
839
+
840
+ ```python
841
+ cert_pem = await client.auth.fetch_peer_cert({"aid": "bob.example.com"})
842
+ ```
843
+
844
+ | 语言 | 方法名 |
845
+ |------|--------|
846
+ | Python | `await client.auth.fetch_peer_cert(params)` |
847
+ | TypeScript | `await client.auth.fetchPeerCert(params)` |
848
+ | JavaScript | `await client.auth.fetchPeerCert(params)` |
849
+ | Go | `client.Auth.FetchPeerCert(ctx, aid, certFingerprint)` |
850
+
851
+ ---
852
+
776
853
  ### `await sign_agent_md(content: str, aid: str | None = None) -> str`
777
854
 
778
855
  > **⚠️ Deprecated。** 主要场景请改用 `client.publish_agent_md(path)`,它内部已包含读文件 + 签名 + 上传一整套流程。`sign_agent_md` 仅作为离线签名(先签名后异步发布、给非 SDK 渠道发送等)的底层工具继续保留,未来版本将移除。
@@ -9,7 +9,8 @@ AUNError
9
9
  ├── ConnectionError # 网络连接失败
10
10
  ├── TimeoutError # 操作超时
11
11
  ├── AuthError # 认证失败(code: 4001/4010/-32001/-32003)
12
- └── CertificateRevokedError # 证书已吊销(code: -32050)
12
+ ├── CertificateRevokedError # 证书已吊销(code: -32050)
13
+ │ └── IdentityConflictError # 身份冲突(code: 4090)
13
14
  ├── PermissionError # 权限不足(code: 4030/403/-32004)
14
15
  ├── ValidationError # 参数校验失败(code: 4000/-32600/-32601/-32602)
15
16
  ├── NotFoundError # 资源不存在(code: 4040/404/-32008)
@@ -67,6 +68,7 @@ except AUNError as e:
67
68
  | -32042 | 成员承诺验证失败 | `E2EEGroupCommitmentInvalidError` |
68
69
  | -32043 | 密钥请求者非群成员 | `E2EEGroupNotMemberError` |
69
70
  | -32044 | 群消息解密失败 | `E2EEGroupDecryptFailedError` |
71
+ | 4090 | 身份冲突 | `IdentityConflictError` |
70
72
  | -32050 | 证书已吊销 | `CertificateRevokedError` |
71
73
  | -32051 | 客户端签名验证失败 | `ClientSignatureError` |
72
74
  | -33001 | 群组不存在 | `GroupNotFoundError` |
@@ -136,6 +138,22 @@ await client.call("message.send", {...})
136
138
  # 协议层定义的错误语义,当前 Python SDK 的部分路径表现为返回 None、拒绝状态或跳过自动解密,不一定抛出对应异常
137
139
  ```
138
140
 
141
+ ### 身份冲突(v0.3.4+)
142
+
143
+ ```python
144
+ from aun_core import IdentityConflictError
145
+
146
+ try:
147
+ await client.auth.register_aid({"aid": "alice.agentid.pub"})
148
+ except IdentityConflictError as e:
149
+ # e.code == 4090
150
+ # 场景 1:AID 已被他人注册(公钥不匹配)→ 换一个 AID
151
+ # 场景 2:本地有身份但服务端无记录 → 清理本地目录后重试
152
+ print(f"身份冲突: {e}")
153
+ ```
154
+
155
+ 跨语言类名统一为 `IdentityConflictError`(Python / Go / TS / JS)。
156
+
139
157
  ### 连接状态错误
140
158
 
141
159
  ```python
@@ -9,9 +9,9 @@
9
9
  ```python
10
10
  async def ensure_connected(client: AUNClient, aid: str) -> str:
11
11
  try:
12
- await client.auth.create_aid({"aid": aid})
12
+ await client.auth.register_aid({"aid": aid})
13
13
  except Exception as e:
14
- print(f"创建 AID 失败: {e}")
14
+ print(f"注册 AID 失败: {e}")
15
15
  raise
16
16
  auth = await client.auth.authenticate({"aid": aid})
17
17
  await client.connect(auth, {"auto_reconnect": True})
@@ -51,9 +51,9 @@ recv_cursor = r.get("latest_seq", 0)
51
51
  # 推荐:用应用名作为 aun_path,多个 AID 共存于同一目录
52
52
  client = AUNClient({"aun_path": "~/.aun/myapp"})
53
53
 
54
- # 创建不同的 AID,各自数据自动隔离
55
- await client.auth.create_aid({"aid": "alice.agentid.pub"})
56
- await client.auth.create_aid({"aid": "bob.agentid.pub"})
54
+ # 注册不同的 AID,各自数据自动隔离
55
+ await client.auth.register_aid({"aid": "alice.agentid.pub"})
56
+ await client.auth.register_aid({"aid": "bob.agentid.pub"})
57
57
  # 数据分别在 ~/.aun/myapp/AIDs/alice.agentid.pub/ 和 bob.agentid.pub/ 下
58
58
  ```
59
59
 
@@ -87,3 +87,18 @@ async def main():
87
87
  - RPC 方法手册:`../src/aun_core/docs/skill/rpc-manual/`
88
88
  - 可运行示例:`../src/aun_core/docs/skill/examples/`
89
89
  - GitHub:https://github.com/ModelUnion/aun-sdk-core
90
+
91
+ ---
92
+
93
+ ## 7. Flow Control(v0.3.4+)
94
+
95
+ SDK 内部自动管理 RPC 并发,应用层无需配置:
96
+
97
+ | 机制 | 说明 |
98
+ |------|------|
99
+ | RPC 并发上限 | 全局最多 16 个并发 RPC 请求 |
100
+ | 后台 RPC 限制 | 后台任务(prekey 上传、token 刷新等)额外限制为 8 个 |
101
+ | Pull Gate | 同一 namespace/group 的 pull 操作自动序列化,防止并发 pull 导致重复消息 |
102
+ | 队列超时 | 排队等待超过 timeout 时抛 `TimeoutError("rpc queue timeout before send: {method}")` |
103
+
104
+ 这些限制在高并发场景下保护服务端不被单客户端打满,同时避免 pull 竞态导致的消息乱序。应用层只需正常调用 `client.call()`,SDK 自动排队和限流。