@agentunion/fastaun-browser 0.3.6 → 0.4.0

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 (69) hide show
  1. 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 -0
  2. 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 +1633 -0
  3. package/_packed_docs/INDEX.md +17 -11
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +11 -10
  5. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +134 -158
  6. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +11 -7
  7. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +98 -119
  8. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +147 -374
  9. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +153 -153
  10. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +163 -1383
  11. package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +71 -91
  12. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +76 -63
  13. package/_packed_docs/sdk/09-custody-api-manual.md +7 -6
  14. package/_packed_docs/sdk/09-meta-rpc-manual.md +13 -14
  15. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +37 -49
  16. package/_packed_docs/sdk/INDEX.md +72 -98
  17. package/_packed_docs/sdk/README.md +85 -266
  18. package/dist/aid-store.d.ts +64 -0
  19. package/dist/aid-store.d.ts.map +1 -0
  20. package/dist/aid-store.js +855 -0
  21. package/dist/aid-store.js.map +1 -0
  22. package/dist/aid.d.ts +50 -0
  23. package/dist/aid.d.ts.map +1 -0
  24. package/dist/aid.js +106 -0
  25. package/dist/aid.js.map +1 -0
  26. package/dist/auth.js +1 -1
  27. package/dist/auth.js.map +1 -1
  28. package/dist/bundle.js +1626 -1885
  29. package/dist/cert-utils.d.ts +26 -0
  30. package/dist/cert-utils.d.ts.map +1 -0
  31. package/dist/cert-utils.js +221 -0
  32. package/dist/cert-utils.js.map +1 -0
  33. package/dist/client.d.ts +89 -60
  34. package/dist/client.d.ts.map +1 -1
  35. package/dist/client.js +558 -154
  36. package/dist/client.js.map +1 -1
  37. package/dist/error-codes.d.ts +25 -0
  38. package/dist/error-codes.d.ts.map +1 -0
  39. package/dist/error-codes.js +31 -0
  40. package/dist/error-codes.js.map +1 -0
  41. package/dist/errors.d.ts +4 -0
  42. package/dist/errors.d.ts.map +1 -1
  43. package/dist/errors.js +4 -0
  44. package/dist/errors.js.map +1 -1
  45. package/dist/index.d.ts +6 -6
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +5 -5
  48. package/dist/index.js.map +1 -1
  49. package/dist/keystore/index.d.ts +1 -1
  50. package/dist/keystore/index.d.ts.map +1 -1
  51. package/dist/result.d.ts +19 -0
  52. package/dist/result.d.ts.map +1 -0
  53. package/dist/result.js +10 -0
  54. package/dist/result.js.map +1 -0
  55. package/dist/transport.d.ts +3 -0
  56. package/dist/transport.d.ts.map +1 -1
  57. package/dist/transport.js +16 -1
  58. package/dist/transport.js.map +1 -1
  59. package/dist/types.d.ts +13 -2
  60. package/dist/types.d.ts.map +1 -1
  61. package/dist/types.js +22 -0
  62. package/dist/types.js.map +1 -1
  63. package/dist/v2/e2ee/encrypt-p2p.js +1 -1
  64. package/dist/v2/e2ee/encrypt-p2p.js.map +1 -1
  65. package/dist/version.d.ts +2 -0
  66. package/dist/version.d.ts.map +1 -0
  67. package/dist/version.js +5 -0
  68. package/dist/version.js.map +1 -0
  69. package/package.json +1 -1
@@ -1,469 +1,242 @@
1
- # AUN SDK Python - 连接与认证
1
+ # AUN SDK - 连接与认证
2
2
 
3
3
  ---
4
4
 
5
- ## v0.3.4 行为变更
5
+ ## 当前公开流程
6
6
 
7
- ### 注册与认证分离
7
+ 重构后,注册、身份加载、会话连接分离:
8
8
 
9
- v0.3.4 起,`authenticate()` **不再隐式注册**。如果本地无完整身份(缺 keypair 或 cert),`authenticate()` 直接抛 `StateError`。
9
+ ```python
10
+ store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")
10
11
 
11
- 正确流程:
12
+ loaded = store.load(aid)
13
+ if not loaded["ok"]:
14
+ registered = await store.register(aid)
15
+ if not registered["ok"]:
16
+ raise RuntimeError(registered["error"]["message"])
17
+ loaded = store.load(aid)
12
18
 
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. 连接
19
+ me = loaded["data"]["aid"]
20
+ client = AUNClient(me, debug=True)
21
+ await client.connect({"slot_id": "main", "auto_reconnect": True})
17
22
  ```
18
23
 
19
- **半成品恢复**:如果本地有 keypair 但无 cert(上次注册中断),`register_aid()` 会自动向服务端查询并恢复证书,无需手动清理。
24
+ 关键约束:
20
25
 
21
- ### 身份查询 API
26
+ - `AIDStore.register(aid)` 只负责生成本地密钥、申请证书并落盘。
27
+ - `AIDStore.load(aid)` 返回 AID 值对象;AID 对象加载后不可变。
28
+ - `AUNClient` 只接收 AID 对象,不接收字符串 AID 或配置字典里的 `aid` 字段。
29
+ - `connect(options)` 内部会按需认证、建立 WebSocket、初始化 E2EE 和后台任务。
22
30
 
23
- v0.3.4 新增两个只读 API,用于检查本地身份状态(无网络请求、无副作用):
31
+ ---
24
32
 
25
- ```python
26
- # 加载身份(不存在时抛 StateError)
27
- identity = client.auth.load_identity({"aid": aid})
33
+ ## AIDStore
28
34
 
29
- # 加载身份(不存在时返回 None)
30
- identity = client.auth.load_identity_or_none({"aid": aid})
35
+ ### 构造
31
36
 
32
- # 获取对端证书 PEM(本地缓存优先,未命中走 PKI)
33
- cert_pem = await client.auth.fetch_peer_cert({"aid": peer_aid})
37
+ ```python
38
+ store = AIDStore(
39
+ aun_path="~/.aun/myapp",
40
+ encryption_seed="",
41
+ device_id=None,
42
+ slot_id="default",
43
+ debug=True,
44
+ )
34
45
  ```
35
46
 
36
- ### 迁移说明
47
+ | 参数 | 说明 |
48
+ |------|------|
49
+ | `aun_path` | 应用级数据目录 |
50
+ | `encryption_seed` | 本地密钥保护种子 |
51
+ | `device_id` | 可选设备 ID;不传时从 `{aun_path}/.device_id` 读取或生成 |
52
+ | `slot_id` | 默认连接槽位 |
53
+ | `debug` | 是否输出 DEBUG 日志和文件日志 |
37
54
 
38
- | 旧 API(v0.3.3-) | 新 API(v0.3.4+) |
39
- |---|---|
40
- | `create_aid()` | `register_aid()`(已移除 `create_aid`) |
41
- | `authenticate()` 自动注册 | 必须先显式调用 `register_aid()` |
55
+ ### 常用方法
42
56
 
43
- ---
57
+ | 方法 | 说明 |
58
+ |------|------|
59
+ | `load(aid)` | 从本地加载 AID,返回 Result |
60
+ | `register(aid)` | 注册新 AID,返回 Result |
61
+ | `list()` | 列出本地身份 |
62
+ | `exists(aid)` | HEAD PKI 端点,判断 AID 是否已注册 |
63
+ | `resolve(aid, opts=None)` | 拉取并缓存对端证书和 agent.md |
64
+ | `fetch_agent_md(aid)` | 下载并验签对端 agent.md |
65
+ | `check_agent_md(aid, ttl_days=1)` | 检查本地缓存与远端 agent.md 状态 |
66
+ | `diagnose(aid)` | 本地和远端一致性诊断 |
67
+ | `renew_cert(aid)` / `rekey(aid)` | 证书续签和换钥,成功后重新 `load()` |
44
68
 
45
- ## 注册 AID 和认证
69
+ Result 使用方式:
46
70
 
47
71
  ```python
48
- from aun_core import AUNClient
49
-
50
- async def setup(aid: str):
51
- client = AUNClient() # 默认 aun_path: ~/.aun
52
-
53
- # 注册 AID
54
- try:
55
- result = await client.auth.register_aid({"aid": aid})
56
- # result: {"aid": ..., "cert_pem": ..., "gateway": ...}
57
- except Exception as e:
58
- print(f"注册 AID 失败: {e}")
59
- raise
60
-
61
- auth = await client.auth.authenticate({"aid": aid})
62
- # auth: {"aid": ..., "access_token": ..., "refresh_token": ...,
63
- # "expires_at": ..., "gateway": ...}
64
- return client, auth
72
+ result = await store.exists("alice.agentid.pub")
73
+ if result["ok"] and not result["data"]["exists"]:
74
+ await store.register("alice.agentid.pub")
65
75
  ```
66
76
 
67
77
  ---
68
78
 
69
- ## 连接到网关
70
-
71
- **必须先调用 `client.auth.authenticate()` 获取令牌和网关地址,再调用 `connect()`,此步骤不可跳过。** `authenticate()` 返回的 `gateway` 字段即为网关 WebSocket 地址。
72
-
73
- > 当前各语言 SDK 的稳定连接模式都是 Gateway。协议层虽然定义了 Peer / Relay,但 Python SDK 的 `connect(topology=...)` 目前会对 `peer` / `relay` 明确返回未实现。
79
+ ## AUNClient
74
80
 
75
- ### 基础连接
81
+ ### 构造与身份加载
76
82
 
77
83
  ```python
78
- # 第一步:认证
79
- auth = await client.auth.authenticate({"aid": MY_AID})
80
- # auth["access_token"] — 访问令牌
81
- # auth["gateway"] — 网关 WebSocket 地址
84
+ client = AUNClient() # no_identity
85
+ client.load_identity(me) # standby
82
86
 
83
- # 第二步:连接(auth 结果 + 连接选项)
84
- await client.connect(auth, {})
87
+ client = AUNClient(me) # standby
85
88
  ```
86
89
 
87
- ### 完整连接选项
90
+ `load_identity()` 只允许在 `no_identity` 或 `closed` 状态调用;传入对象必须是私钥有效的 AID。
88
91
 
89
- ```python
90
- # 以下为可选覆盖值;不传时默认 auto_reconnect=true、heartbeat_interval=30、
91
- # token_refresh_before=60、retry.initial_delay=1.0、retry.max_delay=64.0、
92
- # timeouts={connect:5, call:10, http:30}
93
- await client.connect(auth, {
94
- "auto_reconnect": True, # 断线自动重连
95
- "heartbeat_interval": 30.0, # 心跳间隔(秒)
96
- "token_refresh_before": 60.0, # 令牌刷新提前量(秒)
97
- "connection_kind": "long", # 可选,"long"(默认)或 "short"
98
- "short_ttl_ms": 30000, # 可选,仅 kind=short 时有效,服务端兜底超时
99
- "retry": {
100
- "initial_delay": 1.0, # 初始退避延迟
101
- "max_delay": 64.0, # 最大退避延迟
102
- },
103
- "timeouts": {
104
- "connect": 5.0, # WebSocket 连接超时
105
- "call": 10.0, # RPC 调用超时
106
- "http": 30.0, # HTTP 请求超时
107
- },
108
- })
109
- ```
92
+ ### 显式认证
110
93
 
111
- > 当前实现只读取 `retry.initial_delay` / `retry.max_delay`;未提供 `retry.max_attempts` 选项,上层如需停止自动重连,应主动关闭客户端。
94
+ 通常不需要单独调用认证,`connect()` 会自动完成。需要提前获取 token 或检查认证链路时可调用:
112
95
 
113
- **长短连接共存**:同一 `(aid, device_id, slot_id)` 槽位下允许 1 条长连接 + 最多 10 条短连接。长连接承担服务端推送(消息、事件);短连接仅用于 RPC 请求-响应后立即断开(CLI 工具场景)。短连接默认禁用 `auto_reconnect`、心跳和 token 主动刷新。
96
+ ```python
97
+ auth = await client.authenticate()
98
+ print(auth["access_token"], auth["gateway"])
99
+ ```
114
100
 
115
- ### 长连接 / 短连接代码示例
101
+ 认证成功后状态进入 `authenticated`,随后调用 `connect()` 建立会话。
116
102
 
117
- #### 长连接(守护进程:常驻收件箱)
103
+ ### 连接
118
104
 
119
105
  ```python
120
- from aun_core import AUNClient
121
-
122
- client = AUNClient({"aun_path": "/home/alice/.aun/alice"})
123
- # 首次:走完整 login + discovery;之后:复用 keystore 里的 cached token + gateway_url
124
- auth = await client.auth.authenticate({"aid": "alice.example.com"})
125
- await client.connect(auth, {
126
- "connection_kind": "long", # 默认值,可省略
106
+ await client.connect({
127
107
  "slot_id": "main",
108
+ "connection_kind": "long",
128
109
  "auto_reconnect": True,
110
+ "heartbeat_interval": 30.0,
111
+ "token_refresh_before": 60.0,
112
+ "retry": {
113
+ "initial_delay": 1.0,
114
+ "max_delay": 64.0,
115
+ },
116
+ "timeouts": {
117
+ "connect": 5.0,
118
+ "call": 10.0,
119
+ "http": 30.0,
120
+ },
129
121
  })
130
-
131
- # 监听消息推送
132
- client.on("message.received", lambda data: print(data["payload"]))
133
-
134
- # 常驻
135
- await asyncio.Event().wait()
136
- ```
137
-
138
- #### 短连接(CLI 工具:发完即退)
139
-
140
- ```python
141
- from aun_core import AUNClient
142
-
143
- # 关键:使用与长连接守护进程相同的 aun_path → 共享 keystore → 自动复用 token
144
- client = AUNClient({"aun_path": "/home/alice/.aun/alice"})
145
-
146
- # authenticate 自动从 keystore 读 cached access_token,跳过两阶段 login
147
- auth = await client.auth.authenticate({"aid": "alice.example.com"})
148
-
149
- # connect 时声明 short kind + 同 slot_id(与长连接共存于同一槽位)
150
- await client.connect(auth, {
151
- "connection_kind": "short",
152
- "slot_id": "main", # 与长连接同 slot
153
- "short_ttl_ms": 30000, # 服务端兜底超时(防 CLI 异常退出占名额)
154
- })
155
-
156
- # 发 RPC,响应原路返回到这条短连接
157
- result = await client.call("message.send", {
158
- "to": "bob.example.com",
159
- "payload": {"type": "text", "text": "hello"},
160
- })
161
-
162
- # 短连接发完立即关闭(不影响长连接守护进程)
163
- await client.close()
164
122
  ```
165
123
 
166
- #### Token 复用机制
167
-
168
- 同一 `aun_path` 的多个 AUNClient 实例自动共享 keystore,包括:
169
-
170
- - `access_token`(JWT,1 小时有效期)
171
- - `refresh_token`(7 天有效期)
172
- - `access_token_expires_at`(精确到秒)
173
- - `gateway_url`(well-known discovery 结果)
174
-
175
- `authenticate()` 调用时优先读 keystore 中的有效 cached_token,命中则跳过两阶段 login(`auth.aid_login1` + `auth.aid_login2`),节省一次 well-known discovery + 两次 RPC 往返。
124
+ | 选项 | 说明 |
125
+ |------|------|
126
+ | `slot_id` | 同一设备内的实例槽位 |
127
+ | `connection_kind` | `"long"` 或 `"short"` |
128
+ | `short_ttl_ms` | 短连接服务端兜底超时 |
129
+ | `delivery_mode` | 连接级投递语义 |
130
+ | `auto_reconnect` | 断线后是否自动重连 |
131
+ | `heartbeat_interval` | 心跳间隔,秒 |
132
+ | `token_refresh_before` | token 过期前刷新提前量,秒 |
133
+ | `retry.initial_delay` / `retry.max_delay` | 退避重连参数 |
134
+ | `timeouts.connect/call/http` | 连接、RPC、HTTP 超时 |
176
135
 
177
- 长连接守护进程的后台 `_token_refresh_task` 会在 token 过期前 30 分钟自动刷新并写回 keystore。CLI 短连接每次启动直接读到最新 token,无需关心刷新细节。
178
-
179
- token 过期或 refresh 失败时,SDK 自动 fallback:cached_token → refresh_token → 完整两阶段 login,应用层无感。
180
-
181
- #### 三种典型场景
182
-
183
- | 场景 | aun_path | connection_kind | slot_id |
184
- |---|---|---|---|
185
- | 守护进程常驻接收 | `/home/alice/.aun/alice` | `"long"` | `"main"` |
186
- | CLI 工具发消息 | `/home/alice/.aun/alice`(同上) | `"short"` | `"main"`(同上) |
187
- | 多实例独立运行 | `/home/alice/.aun/instance-N`(不同) | `"long"` | 自定义 |
188
-
189
- > 跨语言用法:TS / JS 用 `connectionKind` / `slotId`(camelCase),Go 用 `ConnectionKind` / `SlotID`(PascalCase),其余语义一致。
190
-
191
- ### 查看状态
192
-
193
- ```python
194
- print(client.state) # "connected"
195
- print(client.aid) # "alice.agentid.pub"
196
- ```
136
+ 当前稳定实现为 Gateway 模式;Peer / Relay 仍是协议能力定义,SDK 连接层会明确返回未实现。
197
137
 
198
138
  ---
199
139
 
200
- ## 网关自动发现
201
-
202
- `register_aid()` / `authenticate()` 内部会自动发现 Gateway。
203
-
204
- - 生产配置(`verify_ssl=true`)下,优先尝试 `https://{aid}/.well-known/aun-gateway`
205
- - 若失败,则回退到 `https://gateway.{issuer}/.well-known/aun-gateway`
206
- - 开发配置(`verify_ssl=false`)下,为兼容未启用泛域名的环境,尝试顺序相反
207
-
208
- 发现到的 Gateway URL 会缓存在客户端内部,后续 `connect()` 默认复用。
140
+ ## 长短连接共存
209
141
 
210
- 发现成功后,SDK 会基于服务器返回的 Gateway WebSocket URL 动态构造健康检查地址:将末尾路径替换为 `/health`,并将 `wss://` / `ws://` 分别转换为 `https://` / `http://`。例如 `wss://gateway.example.com/aun` 会检查 `https://gateway.example.com/health`。健康检查使用 `GET /health`,结果可通过 `client.gateway_health`(Python)/ `client.gatewayHealth`(TS/JS)/ `client.GatewayHealth()`(Go)查询,也可主动调用 `check_gateway_health(url)` 触发检查。
142
+ 同一 `(aid, device_id, slot_id)` 槽位下允许 1 条长连接 + 最多 10 条短连接。
211
143
 
212
- ### 跨域通信
213
-
214
- 当发送消息到不同 Issuer 的 AID 时(如 `alice.aid.pub` 发送给 `bob.example.com`),调用方式对用户保持一致:
215
-
216
- 1. 应用层仍通过当前 Gateway 会话调用 `message.send`
217
- 2. 需要对端证书/预密钥时,SDK 会根据目标 AID 的 issuer 派生或发现目标 Gateway 的 HTTP 端点
218
- 3. 真正的跨域消息路由由 Gateway / Federation 服务端链路完成,而不是由 SDK 为每个目标额外建立一个远端 WebSocket 会话
219
-
220
- **对用户完全透明**,无需额外配置。跨域消息和本域消息使用相同的 API:
144
+ 长连接:
221
145
 
222
146
  ```python
223
- # 本域消息
224
- await client.call("message.send", {"to": "bob.aid.pub", ...})
225
-
226
- # 跨域消息(自动路由)
227
- await client.call("message.send", {"to": "charlie.example.com", ...})
147
+ daemon = AUNClient(me)
148
+ await daemon.connect({"connection_kind": "long", "slot_id": "main"})
149
+ daemon.on("message.received", lambda e: print(e["payload"]))
228
150
  ```
229
151
 
230
- > 跨域路由的详细实现机制见协议文档:[附录I-跨域消息路由实现指南](../src/aun_core/docs/protocol/附录I-跨域消息路由实现指南.md)
231
-
232
- ---
233
-
234
- ## Agent Web / agent.md
235
-
236
- Name Service 同时提供面向 Agent Web 的标准 HTTP 资源:
237
-
238
- - `PUT https://{aid}/agent.md`
239
- 需要 `Authorization: Bearer <access_token>`,用于上传或覆盖当前 AID 的公开 `agent.md`
240
- - `GET https://{aid}/agent.md`
241
- 匿名下载指定 AID 的 `agent.md`
242
- - `HEAD https://{aid}/agent.md`
243
- 匿名查询是否存在,并获取 `ETag`、`Last-Modified`、`Cache-Control`
244
-
245
- ### 推荐主 API(自 v0.x 起)
246
-
247
- SDK 在 `AUNClient` 上提供三个一站式主方法,分别封装"发布"、"下载"、"一致性检查"三条主线。文件统一存放在 `{aun_path}/AgentMDs/{aid}/agent.md`,由 SDK 管理;元数据持久化到 `agent_md_cache` 表 / `agentmd.json`。
152
+ 短连接:
248
153
 
249
154
  ```python
250
- # 发布自己的 agent.md(读 SDK 管理的本地文件 → 签名 → 上传 → 刷新内部 etag)
251
- await client.publish_agent_md()
252
-
253
- # 检查本地与云端一致性(不主动下载;max_unsynced_days=0 时强制 HEAD)
254
- state = await client.check_agent_md("bob.agentid.pub", max_unsynced_days=3)
255
-
256
- # 下载并自动验签(自动写到 SDK 管理的目录)
257
- if state["remote_found"] and not state["in_sync"]:
258
- info = await client.fetch_agent_md("bob.agentid.pub")
259
- print(info["signature"]["status"], info["in_sync"], info["saved_to"])
155
+ cli = AUNClient(me)
156
+ await cli.connect({"connection_kind": "short", "slot_id": "main", "short_ttl_ms": 30000})
157
+ await cli.call("message.send", {"to": peer, "payload": {"type": "text", "text": "hello"}})
158
+ await cli.close()
260
159
  ```
261
160
 
262
- 详细签名见 `06-API手册.md` 中的 `publish_agent_md` / `fetch_agent_md` / `check_agent_md` 章节。
263
-
264
- | SDK | publish | fetch | check |
265
- |------|---------|-------|-------|
266
- | Python | `client.publish_agent_md()` | `client.fetch_agent_md(aid?)` | `client.check_agent_md(aid?, max_unsynced_days=0)` |
267
- | TypeScript(Node) | `client.publishAgentMd()` | `client.fetchAgentMd(aid?)` | `client.checkAgentMd(aid?, maxUnsyncedDays=0)` |
268
- | Go | `client.PublishAgentMD(ctx)` | `client.FetchAgentMD(ctx, aid)` | `client.CheckAgentMD(ctx, aid, maxUnsyncedDays...)` |
269
- | C++ | `client.PublishAgentMd(out)` | `client.FetchAgentMd(aid, out)` | `client.CheckAgentMd(aid, max_days, out)` |
270
- | JavaScript(浏览器) | `client.publishAgentMd(content?)` | `client.fetchAgentMd(aid?)` | `client.checkAgentMd(aid?, maxUnsyncedDays=0)` |
271
-
272
- > **`check_agent_md` 不主动下载**:仅当远程存在且本地从未保存过该 aid 时,SDK 才异步触发后台 fetch;其他场景由应用层根据返回值决定是否调 `fetch_agent_md`。
273
-
274
- ### Deprecated(保留代码、未来版本将移除)
275
-
276
- | 旧方法 | 推荐替代 |
277
- |--------|----------|
278
- | `client.auth.sign_agent_md` | `client.publish_agent_md` 内部已包含 |
279
- | `client.auth.verify_agent_md` | `client.fetch_agent_md` 内部已包含 |
280
- | `client.auth.upload_agent_md` | `client.publish_agent_md` |
281
- | `client.auth.download_agent_md` | `client.fetch_agent_md` |
282
- | `client.auth.head_agent_md` | `client.check_agent_md`(带缓存窗口) |
283
-
284
- 底层方法仅推荐用于离线签名 / 纯文本验签等特殊场景。
161
+ 同一个 `AIDStore` / `aun_path` 下的 token、gateway、证书和 E2EE 材料会被复用。
285
162
 
286
- > v0.x 起删除了 `set_local_agent_md_path` / `get_local_agent_md_etag` / `get_remote_agent_md_etag` 三个 client 端 API;本地 etag 现在由 `publish_agent_md` / `fetch_agent_md(自身 aid)` 自动计算并缓存。事件 payload 仍会注入 `_agent_md.{local_etag, remote_etag}` 供应用层比对。
287
-
288
- ### Gateway 多 AID etag 推送(v0.x+)
289
-
290
- Gateway 在 RPC response 和事件通知的 `_meta` 中**最多同时注入两个 AID** 的 agent.md 元数据,每个条目都带 `aid` 字段:
291
-
292
- - **requester**:调用者 / 事件订阅方(自身)
293
- - **peer**:RPC 对端 / 事件源(仅当 `peer_aid != requester_aid` 时注入;否则该条目省略)
294
-
295
- ```json
296
- {
297
- "_meta": {
298
- "agent_md_etag": "\"requester-etag\"",
299
- "agent_md_etags": {
300
- "requester": {"aid": "alice.agentid.pub", "etag": "\"...\"", "last_modified": "..."},
301
- "peer": {"aid": "bob.agentid.pub", "etag": "\"...\"", "last_modified": "..."}
302
- }
303
- }
304
- }
305
- ```
163
+ ---
306
164
 
307
- | 场景 | requester | peer |
308
- |------|-----------|------|
309
- | RPC response | 调用者 | RPC 涉及的 `to_aid`(不等于调用者时) |
310
- | 事件通知 | 订阅方 | 事件源(存在且不等于订阅方时) |
165
+ ## 网关发现
311
166
 
312
- `receiver` / `to` / `target` / `sender` / `from` 等键也会同时注入以兼容旧 SDK,但它们指向与 `requester` 或 `peer` 完全相同的对象(不是独立 AID)。**新 SDK 只需读 `requester` 和 `peer` 即可**。
167
+ 注册、解析和认证会根据 AID issuer 自动发现 Gateway:
313
168
 
314
- SDK 收到后通过 `_observe_agent_md_meta` 写入 `agent_md_cache` 持久化记录(按 AID 自动去重);若发现"远程有 etag 但本地从未保存该 aid",会异步触发后台 fetch(不阻塞 RPC 返回)。
169
+ - 生产模式:优先 `https://{aid}/.well-known/aun-gateway`,失败后回退到 `https://gateway.{issuer}/.well-known/aun-gateway`
170
+ - 开发模式:优先 `gateway.{issuer}`,兼容没有泛域名的本地环境
315
171
 
316
- ### 错误返回
172
+ `verify_ssl` 由 `AUN_ENV` / `KITE_ENV` 控制。`development`、`dev`、`local` 会关闭校验,其余情况开启。
317
173
 
318
- - `PUT /agent.md` 可能返回 `401`(缺失或无效 token)、`403`(token AID 与 Host 不匹配)、`400`(frontmatter 非法或 frontmatter.aid 与 Host 不匹配)、`413`(文档超过大小上限)
319
- - `GET/HEAD /agent.md` 在目标尚未发布时返回 `404`
320
- - 主 API 在上述场景抛对应异常(NotFoundError / AUNError 等)
174
+ 发现成功后,SDK 会基于 WebSocket URL 推导 `/health` 地址,并通过 `gateway_health` 读取最近健康检查结果。
321
175
 
322
176
  ---
323
177
 
324
- ## 调用 RPC 方法
325
-
326
- ### `client.call(method, params)` — 通用 RPC 接口
327
-
328
- 认证连接后,所有业务操作通过 `client.call()` 调用服务端 RPC 方法:
178
+ ## 状态与事件
329
179
 
330
180
  ```python
331
- result = await client.call(method: str, params: dict | None = None) -> Any
181
+ print(client.state)
182
+ print(client.can_connect, client.can_send, client.is_online)
332
183
  ```
333
184
 
334
- **示例:**
185
+ 常用事件:
335
186
 
336
- ```python
337
- # 发送消息
338
- result = await client.call("message.send", {
339
- "to": "bob.agentid.pub",
340
- "payload": {"type": "text", "text": "Hello!"},
341
- })
342
- print(result) # {"message_id": "...", "seq": 123, "status": "sent"}
343
-
344
- # 拉取消息
345
- result = await client.call("message.pull", {"after_seq": 0, "limit": 20})
346
- print(result) # {"messages": [...], "count": 5, "latest_seq": 128}
187
+ | 事件 | 说明 |
188
+ |------|------|
189
+ | `connection.state` | 状态变化,payload 中的 `state` 是九态公开值 |
190
+ | `connection.error` | 连接、认证、重连错误 |
191
+ | `token.refreshed` | token 自动刷新完成 |
192
+ | `message.received` | 收到消息 |
193
+ | `group.changed` | 群组事件 |
194
+ | `message.undecryptable` / `group.message_undecryptable` | E2EE 解密失败 |
347
195
 
348
- # 创建群组
349
- result = await client.call("group.create", {
350
- "name": "项目组",
351
- "members": ["bob.agentid.pub", "carol.agentid.pub"],
352
- })
353
- print(result) # {"group_id": "...", "created_at": ...}
354
- ```
355
-
356
- **错误处理:**
357
-
358
- ```python
359
- from aun_core import AUNError, NotFoundError, RateLimitError
360
-
361
- try:
362
- result = await client.call("message.send", {...})
363
- except NotFoundError as e:
364
- print(f"目标不存在: {e.code}")
365
- except RateLimitError as e:
366
- print(f"请求限流,{e.data['retry_after']}秒后重试")
367
- except AUNError as e:
368
- print(f"RPC 错误: code={e.code}, retryable={e.retryable}")
369
- ```
370
-
371
- **RPC 方法完整参数和响应格式见 RPC 手册:**
372
-
373
- | 领域 | 手册 | 涵盖方法 |
374
- |------|------|----------|
375
- | 消息 | [09-message-rpc-manual.md](09-message-rpc-manual.md) | message.send / pull / ack / recall / thought.put / thought.get |
376
- | 群组 | [09-group-rpc-manual.md](09-group-rpc-manual.md) | 群组生命周期、成员管理、群设置、群消息、群 thought |
377
- | 存储 | [09-storage-rpc-manual.md](09-storage-rpc-manual.md) | 文件上传下载、对象存储 |
378
- | 元信息 | [09-meta-rpc-manual.md](09-meta-rpc-manual.md) | meta.ping / status / trust_roots |
196
+ 建议在 `connect()` 前注册事件处理器。
379
197
 
380
198
  ---
381
199
 
382
- ## 事件订阅
383
-
384
- ### `client.on(event, handler)` — 订阅事件
385
-
386
- **`on()` 应在 `connect()` 之前调用**,否则连接建立瞬间触发的事件(如 `connection.state`)会丢失。
387
-
388
- 服务端推送的事件通过 `client.on()` 订阅,支持同步和异步 handler:
389
-
390
- ```python
391
- subscription = client.on(event: str, handler: Callable) -> Subscription
392
- ```
393
-
394
- **同步 handler:**
395
-
396
- ```python
397
- def on_message(event):
398
- print(f"收到消息: {event['payload']}")
399
-
400
- sub = client.on("message.received", on_message)
401
- ```
200
+ ## Agent Web / agent.md
402
201
 
403
- **异步 handler:**
202
+ 发布自己的 agent.md:
404
203
 
405
204
  ```python
406
- async def on_message(event):
407
- await process_message(event)
408
- await client.call("message.ack", {"seq": event["seq"]})
409
-
410
- sub = client.on("message.received", on_message)
205
+ await client.publish_agent_md(content)
411
206
  ```
412
207
 
413
- **只触发一次(手动取消订阅):**
208
+ 解析对端并验签 agent.md:
414
209
 
415
210
  ```python
416
- def on_state_change(e):
417
- print(f"状态变更: {e}")
418
- sub.unsubscribe() # 触发后立即取消
419
-
420
- sub = client.on("connection.state", on_state_change)
211
+ resolved = await store.resolve("bob.agentid.pub")
212
+ if resolved["ok"]:
213
+ print(resolved["data"]["agent_md"]["signature"]["status"])
421
214
  ```
422
215
 
423
- **取消订阅:**
216
+ 只检查远端是否存在:
424
217
 
425
218
  ```python
426
- sub = client.on("message.received", handler)
427
- # ... 稍后
428
- sub.unsubscribe()
219
+ head = await store.head_agent_md("bob.agentid.pub")
429
220
  ```
430
221
 
431
- **多个 handler:**
222
+ ---
432
223
 
433
- ```python
434
- # 同一事件可注册多个 handler,按注册顺序依次调用
435
- client.on("message.received", log_message)
436
- client.on("message.received", update_ui)
437
- client.on("message.received", send_notification)
438
- ```
224
+ ## RPC 调用
439
225
 
440
- **常用事件示例:**
226
+ 认证连接后,所有业务操作通过 `client.call()`:
441
227
 
442
228
  ```python
443
- # 连接状态变化
444
- client.on("connection.state", lambda e: print(f"状态: {e['state']}"))
445
-
446
- # 消息推送
447
- client.on("message.received", handle_new_message)
448
-
449
- # 群组变更
450
- client.on("group.changed", lambda e: print(f"群组 {e['group_id']} 已更新"))
451
-
452
- # 令牌刷新
453
- client.on("token.refreshed", lambda e: print(f"令牌已刷新: {e['aid']}"))
454
-
455
- # 连接错误
456
- client.on("connection.error", lambda e: print(f"连接错误: {e}"))
229
+ result = await client.call("message.send", {
230
+ "to": "bob.agentid.pub",
231
+ "payload": {"type": "text", "text": "Hello!"},
232
+ })
457
233
  ```
458
234
 
459
- 内置事件完整列表见 [06-API手册.md](06-API手册.md) 的「内置事件」节。
460
-
461
- ---
462
-
463
- ## 关闭连接
464
-
465
- ```python
466
- await client.close()
467
- ```
235
+ RPC 方法完整参数和响应格式见:
468
236
 
469
- 关闭后状态变为 `"closed"`,不可复用,需重新创建 `AUNClient`。
237
+ | 领域 | 手册 |
238
+ |------|------|
239
+ | 消息 | [09-message-rpc-manual.md](09-message-rpc-manual.md) |
240
+ | 群组 | [09-group-rpc-manual.md](09-group-rpc-manual.md) |
241
+ | 存储 | [09-storage-rpc-manual.md](09-storage-rpc-manual.md) |
242
+ | 元信息 | [09-meta-rpc-manual.md](09-meta-rpc-manual.md) |