@agentunion/fastaun-browser 0.4.4 → 0.4.6

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 (73) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/_packed_docs/CHANGELOG.md +41 -0
  3. package/_packed_docs/INDEX.md +2 -2
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +1 -1
  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 +73 -84
  6. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +16 -15
  7. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +2 -2
  8. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +22 -5
  9. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +42 -26
  10. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +2 -2
  11. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +61 -35
  12. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +3 -3
  13. package/_packed_docs/sdk/09-message-rpc-manual.md +6 -6
  14. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +6 -4
  15. package/_packed_docs/sdk/INDEX.md +2 -2
  16. package/_packed_docs/sdk/README.md +3 -3
  17. package/dist/agent-md.d.ts +111 -0
  18. package/dist/agent-md.d.ts.map +1 -0
  19. package/dist/agent-md.js +656 -0
  20. package/dist/agent-md.js.map +1 -0
  21. package/dist/aid-store.d.ts +8 -40
  22. package/dist/aid-store.d.ts.map +1 -1
  23. package/dist/aid-store.js +89 -172
  24. package/dist/aid-store.js.map +1 -1
  25. package/dist/auth.d.ts +8 -13
  26. package/dist/auth.d.ts.map +1 -1
  27. package/dist/auth.js +37 -130
  28. package/dist/auth.js.map +1 -1
  29. package/dist/bundle.js +6540 -6033
  30. package/dist/client.d.ts +8 -65
  31. package/dist/client.d.ts.map +1 -1
  32. package/dist/client.js +193 -762
  33. package/dist/client.js.map +1 -1
  34. package/dist/index.d.ts +4 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +3 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/keystore/index.d.ts +49 -22
  39. package/dist/keystore/index.d.ts.map +1 -1
  40. package/dist/keystore/index.js +6 -1
  41. package/dist/keystore/index.js.map +1 -1
  42. package/dist/keystore/indexeddb-identity-store.d.ts +59 -0
  43. package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -0
  44. package/dist/keystore/indexeddb-identity-store.js +489 -0
  45. package/dist/keystore/indexeddb-identity-store.js.map +1 -0
  46. package/dist/keystore/indexeddb-shared.d.ts +76 -0
  47. package/dist/keystore/indexeddb-shared.d.ts.map +1 -0
  48. package/dist/keystore/indexeddb-shared.js +382 -0
  49. package/dist/keystore/indexeddb-shared.js.map +1 -0
  50. package/dist/keystore/indexeddb-token-store.d.ts +119 -0
  51. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -0
  52. package/dist/keystore/indexeddb-token-store.js +1086 -0
  53. package/dist/keystore/indexeddb-token-store.js.map +1 -0
  54. package/dist/keystore/indexeddb.d.ts +11 -1
  55. package/dist/keystore/indexeddb.d.ts.map +1 -1
  56. package/dist/keystore/indexeddb.js +167 -18
  57. package/dist/keystore/indexeddb.js.map +1 -1
  58. package/dist/register-flow.d.ts +53 -0
  59. package/dist/register-flow.d.ts.map +1 -0
  60. package/dist/register-flow.js +401 -0
  61. package/dist/register-flow.js.map +1 -0
  62. package/dist/v2/session/keystore.d.ts +5 -0
  63. package/dist/v2/session/keystore.d.ts.map +1 -1
  64. package/dist/v2/session/keystore.js +29 -0
  65. package/dist/v2/session/keystore.js.map +1 -1
  66. package/dist/version.d.ts +1 -1
  67. package/dist/version.js +1 -1
  68. package/package.json +1 -1
  69. package/_packed_docs/0.4.0_/345/267/256/345/274/202/346/240/270/345/256/236/345/206/263/347/255/226/350/256/260/345/275/225.md +0 -302
  70. 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 +0 -194
  71. package/_packed_docs/AUN_SDK_/351/207/215/346/236/204/345/256/236/346/226/275/350/256/241/345/210/222.md +0 -596
  72. 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 +0 -1698
  73. package/_packed_docs/python-sdk-v2-only-changelog.md +0 -189
package/CHANGELOG.md CHANGED
@@ -6,6 +6,47 @@
6
6
 
7
7
  ---
8
8
 
9
+ ## 0.4.6 — 2026-06-01
10
+
11
+ ### Added
12
+ - **IndexedDB 存储拆分**:将单一 `IndexedDBKeyStore` 拆分为两个专职类:
13
+ - `IndexedDBIdentityStore`(`keystore/indexeddb-identity-store.ts`):负责私钥、密钥对、完整身份、pending 注册、证书、metadata KV。
14
+ - `IndexedDBTokenStore`(`keystore/indexeddb-token-store.ts`):负责 prekeys、群组密钥、sessions、seq 跟踪、agent.md 缓存、群组状态、信任根。
15
+ - 共享基础设施提取到 `keystore/indexeddb-shared.ts`。
16
+ - **`AgentMdManager` 类**(`agent-md.ts`):独立的 agent.md 管理器,支持 ETag/Last-Modified 缓存验证、TTL 策略、内容签名验证、信任根存储(虚拟路径 `indexeddb://trust-roots/...`)。
17
+ - **`KeyStore` 接口新增方法**:`loadCert(aid, certFingerprint?)` / `saveCert(aid, certPem, certFingerprint?, opts?)`。
18
+ - **`RegisterFlow` 新增公开方法**:`validateAidName`、`fetchPeerCert`、`shortRpc`、`generateIdentity`、`newClientNonce`、`verifyPhase1Response`。
19
+ - **`AIDStore` 新增方法**:`downloadAgentMd`(替代 `fetchAgentMd`)、`checkAgentMd`(替代 `headAgentMd`)。
20
+ - **`AUNClient.uploadAgentMd()`**:新增方法,签名并上传当前 AID 的 agent.md。
21
+ - **IndexedDB 新增对象仓库**:`agent_md_cache`、`group_state`、`pending_identities`、`e2ee_sessions`;数据库版本升级至 v7。
22
+ - **导出新增**:`IndexedDBIdentityStore`、`IndexedDBTokenStore`、`TokenStore` 类型。
23
+
24
+ ### Changed
25
+ - **`AUNClient` 架构**:移除内部 agent.md 缓存字段(`_agentMdCache`、`_agentMdFetchInflight` 等),改由 `AgentMdManager` 统一管理。
26
+ - **`AIDStore`**:使用 `IndexedDBIdentityStore` 替代 `IndexedDBKeyStore`;移除内部 `AuthFlow` 实例,改为按需创建。
27
+ - **`AIDStore.fetchAgentMd()`** 重命名为 `downloadAgentMd()`,返回类型同步更新为 `DownloadAgentMdResult`。
28
+ - **私钥加密**:默认启用 AES-256-GCM + PBKDF2(100,000 迭代);支持 `changeSeed()` 密码迁移。
29
+
30
+ ### Removed
31
+ - **`IndexedDBKeyStore` 类**(`keystore/indexeddb.ts`,2280 行):完整移除,功能分解为 `IndexedDBIdentityStore` 和 `IndexedDBTokenStore`。
32
+ - **`FullKeyStore` 类型别名**:不再需要。
33
+ - **`AIDStore.headAgentMd()`**:功能整合到 `AgentMdManager.check()`。
34
+
35
+ ---
36
+
37
+ ## 0.4.5 — 2026-05-31
38
+
39
+ ### Added
40
+ - **`RegisterFlow` 独立类**(`register-flow.ts`):将 AID 注册流程从 `AuthFlow` 中剥离,负责 keypair 生成、服务端 RPC、pending 目录(IndexedDB)原子提交、崩溃恢复。
41
+ - **`TokenStore` 接口**:从 `KeyStore` 中拆分出不含私钥操作的子接口,供 `AuthFlow` 使用。
42
+
43
+ ### Changed
44
+ - **`AuthFlow` 改用 `TokenStore`**:构造参数 `keystore` 重命名为 `tokenStore`,类型收窄为 `TokenStore`;私钥操作全部移出 `AuthFlow`。
45
+ - **`AuthFlow.setIdentity()`**:新增方法,由 `AUNClient` 注入内存私钥;`AuthFlow` 内部不再从 `tokenStore` 解密私钥。
46
+ - **`AIDStore.register()` 私钥写入职责转移**:注册结果由 `AIDStore` 负责调用 `keystore.saveCert` / `saveKeyPair` 写入,与 Python / Go / TS SDK 对齐。
47
+
48
+ ---
49
+
9
50
  ## 0.4.4 — 2026-05-31
10
51
 
11
52
  ### Added
@@ -6,6 +6,47 @@
6
6
 
7
7
  ---
8
8
 
9
+ ## 0.4.6 — 2026-06-01
10
+
11
+ ### Added
12
+ - **IndexedDB 存储拆分**:将单一 `IndexedDBKeyStore` 拆分为两个专职类:
13
+ - `IndexedDBIdentityStore`(`keystore/indexeddb-identity-store.ts`):负责私钥、密钥对、完整身份、pending 注册、证书、metadata KV。
14
+ - `IndexedDBTokenStore`(`keystore/indexeddb-token-store.ts`):负责 prekeys、群组密钥、sessions、seq 跟踪、agent.md 缓存、群组状态、信任根。
15
+ - 共享基础设施提取到 `keystore/indexeddb-shared.ts`。
16
+ - **`AgentMdManager` 类**(`agent-md.ts`):独立的 agent.md 管理器,支持 ETag/Last-Modified 缓存验证、TTL 策略、内容签名验证、信任根存储(虚拟路径 `indexeddb://trust-roots/...`)。
17
+ - **`KeyStore` 接口新增方法**:`loadCert(aid, certFingerprint?)` / `saveCert(aid, certPem, certFingerprint?, opts?)`。
18
+ - **`RegisterFlow` 新增公开方法**:`validateAidName`、`fetchPeerCert`、`shortRpc`、`generateIdentity`、`newClientNonce`、`verifyPhase1Response`。
19
+ - **`AIDStore` 新增方法**:`downloadAgentMd`(替代 `fetchAgentMd`)、`checkAgentMd`(替代 `headAgentMd`)。
20
+ - **`AUNClient.uploadAgentMd()`**:新增方法,签名并上传当前 AID 的 agent.md。
21
+ - **IndexedDB 新增对象仓库**:`agent_md_cache`、`group_state`、`pending_identities`、`e2ee_sessions`;数据库版本升级至 v7。
22
+ - **导出新增**:`IndexedDBIdentityStore`、`IndexedDBTokenStore`、`TokenStore` 类型。
23
+
24
+ ### Changed
25
+ - **`AUNClient` 架构**:移除内部 agent.md 缓存字段(`_agentMdCache`、`_agentMdFetchInflight` 等),改由 `AgentMdManager` 统一管理。
26
+ - **`AIDStore`**:使用 `IndexedDBIdentityStore` 替代 `IndexedDBKeyStore`;移除内部 `AuthFlow` 实例,改为按需创建。
27
+ - **`AIDStore.fetchAgentMd()`** 重命名为 `downloadAgentMd()`,返回类型同步更新为 `DownloadAgentMdResult`。
28
+ - **私钥加密**:默认启用 AES-256-GCM + PBKDF2(100,000 迭代);支持 `changeSeed()` 密码迁移。
29
+
30
+ ### Removed
31
+ - **`IndexedDBKeyStore` 类**(`keystore/indexeddb.ts`,2280 行):完整移除,功能分解为 `IndexedDBIdentityStore` 和 `IndexedDBTokenStore`。
32
+ - **`FullKeyStore` 类型别名**:不再需要。
33
+ - **`AIDStore.headAgentMd()`**:功能整合到 `AgentMdManager.check()`。
34
+
35
+ ---
36
+
37
+ ## 0.4.5 — 2026-05-31
38
+
39
+ ### Added
40
+ - **`RegisterFlow` 独立类**(`register-flow.ts`):将 AID 注册流程从 `AuthFlow` 中剥离,负责 keypair 生成、服务端 RPC、pending 目录(IndexedDB)原子提交、崩溃恢复。
41
+ - **`TokenStore` 接口**:从 `KeyStore` 中拆分出不含私钥操作的子接口,供 `AuthFlow` 使用。
42
+
43
+ ### Changed
44
+ - **`AuthFlow` 改用 `TokenStore`**:构造参数 `keystore` 重命名为 `tokenStore`,类型收窄为 `TokenStore`;私钥操作全部移出 `AuthFlow`。
45
+ - **`AuthFlow.setIdentity()`**:新增方法,由 `AUNClient` 注入内存私钥;`AuthFlow` 内部不再从 `tokenStore` 解密私钥。
46
+ - **`AIDStore.register()` 私钥写入职责转移**:注册结果由 `AIDStore` 负责调用 `keystore.saveCert` / `saveKeyPair` 写入,与 Python / Go / TS SDK 对齐。
47
+
48
+ ---
49
+
9
50
  ## 0.4.4 — 2026-05-31
10
51
 
11
52
  ### Added
@@ -13,7 +13,7 @@
13
13
  | [跨语言容器E2E测试方案](design/跨语言容器E2E测试方案.md) | 多语言 SDK 同网同服、test-runner 控制面的跨语言 E2E 方案 |
14
14
  | [E2EE V2 简化为 1DH + Per-AID Wrap 方案](design/E2EE_V2简化为1DH加Per-AID_Wrap方案.md) | SDK bootstrap 能力声明 + 服务端 policy 控制 1DH/per-AID wrap 的兼容方案 |
15
15
  | [AUN RPC Trace 增强设计](design/2026-05-22-aun-rpc-trace-enhancement.md) | RPC trace 诊断字段与 enter/exit span 设计 |
16
- | [远程 agent.md 缓存与 ETag 透传方案](agent.md/远程agent.md缓存与etag透传方案.md) | 远程 agent.md per-AID 缓存、SQLite 表、消息信封与 RPC 响应 ETag 透传方案 |
16
+ | [远程 agent.md 缓存与 ETag 透传方案](agent.md/远程agent.md缓存与etag透传方案.md) | 远程 agent.md per-AID 本地文件/IndexedDB 缓存、消息信封与 RPC 响应 ETag 透传方案 |
17
17
  | [SDK 文档索引](sdk/INDEX.md) | SDK 使用手册、RPC 手册、E2EE 手册的子索引 |
18
18
  | [SDK 查阅指南](sdk/AUN_DOCS_GUIDE.md) | SDK 文档按行区间渐进式查阅方法 |
19
19
  | [协议文档目录](protocol/) | AUN 协议相关文档 |
@@ -76,7 +76,7 @@
76
76
 
77
77
  ### 远程 agent.md 缓存与 ETag 透传方案
78
78
 
79
- 定义每个远程 AID 在 SDK 内存和 SQLite 中维护一条 `remote_agent_md_cache` 记录,字段包含 `remote_etag`、`local_etag`、`content`、`last_modified`、`fetched_at`、`observed_at` 等。方案同时规定 `message.send` 响应向发送端透传 `to` 的 agent.md ETag,消息信封向接收端透传 `from` 的 agent.md ETag,并给出按需下载、304 处理、竞态和跨 SDK 一致性规则。
79
+ 定义每个远程 AID 在 SDK 内存和本地持久化记录中维护一条 agent.md 状态:Python / TypeScript / Go 使用 `{aun_path}/AIDs/{aid}/agent.md` `agentmd.json`,浏览器 JavaScript 使用 IndexedDB logical key。方案同时规定 `message.send` 响应向发送端透传 `to` 的 agent.md ETag,消息信封向接收端透传 `from` 的 agent.md ETag,并给出按需下载、无条件 GET、304 兼容、竞态和跨 SDK 一致性规则。
80
80
 
81
81
  ### SDK 文档索引
82
82
 
@@ -52,5 +52,5 @@ AUN SDK Core 文档在 `docs/` 下。根级索引为 `docs/INDEX.md`,SDK API
52
52
  | agent.md 远程缓存目标与字段 | `docs/agent.md/远程agent.md缓存与etag透传方案.md` L5-86 |
53
53
  | agent.md ETag 透传时序图 | `docs/agent.md/远程agent.md缓存与etag透传方案.md` L88-185 |
54
54
  | agent.md 服务端与 SDK 实现流程 | `docs/agent.md/远程agent.md缓存与etag透传方案.md` L187-268 |
55
- | agent.md SQLite 表结构、竞态和测试点 | `docs/agent.md/远程agent.md缓存与etag透传方案.md` L270-328 |
55
+ | agent.md 本地持久化、竞态和测试点 | `docs/agent.md/远程agent.md缓存与etag透传方案.md` L269-317 |
56
56
  | SDK API、RPC、E2EE 使用细节 | `docs/sdk/AUN_DOCS_GUIDE.md` |
@@ -8,8 +8,8 @@
8
8
 
9
9
  核心目标:
10
10
 
11
- - 每个远程 AID 在 SDK 本地内存中维护一条 `agent.md` 记录,包含 `remote_etag`、`local_etag`、`content`、`last_modified` 等字段。
12
- - 同一条远程缓存记录持久化到本地 SQLite 表,SDK 启动或内存 miss 时按需加载。
11
+ - 每个远程 AID 在 SDK 本地维护一条 `agent.md` 记录,包含 `remote_etag`、`local_etag`、`content`、`last_modified` 等字段。
12
+ - Python / TypeScript / Go 将正文和元数据持久化到 `{aun_path}/AIDs/{aid}/agent.md` 与 `agentmd.json`;浏览器 JavaScript 使用 IndexedDB 等价 key,存储不可用时退化为内存缓存。
13
13
  - `message.send` 的 RPC 响应携带接收方 `agent.md` ETag,让发送方更新 `to` 的云端版本。
14
14
  - 接收端收到消息信封时携带发送方 `agent.md` ETag,让接收方更新 `from` 的云端版本。
15
15
  - ETag 只作为版本提示,不替代 `agent.md` 内容下载和验签。
@@ -21,7 +21,7 @@
21
21
  1. `message.send` / V2 P2P send:把 `from` 的 `agent.md` ETag 注入消息信封,随消息到达接收端。
22
22
  2. `message.send` RPC response:把 `to` 的 `agent.md` ETag 注入响应 `_meta`,返回发送端。
23
23
 
24
- 注意:服务端注入的 ETag 只能代表云端版本。SDK 本地必须区分“观察到的远端云端 ETag”和“当前本地内容对应的 ETag”。字段命名固定为 `remote_etag` 和 `local_etag`,其中 `remote_etag` 表示远端云端版本,`local_etag` 表示本地 `content` 对应版本。不能在只有远端 ETag、没有内容的情况下直接覆盖 `local_etag`,否则后续 `If-None-Match` 命中 304 时本地可能没有可用内容。
24
+ 注意:服务端注入的 ETag 只能代表云端版本。SDK 本地必须区分“观察到的远端云端 ETag”和“当前本地内容对应的 ETag”。字段命名固定为 `remote_etag` 和 `local_etag`,其中 `remote_etag` 表示远端云端版本,`local_etag` 表示本地 `content` 对应版本。下载必须始终使用无条件 GET,不能把 `remote_etag` 或 `local_etag` 放进 `If-None-Match` / `If-Modified-Since`,否则会把版本提示误用成 HTTP 缓存状态。
25
25
 
26
26
  ## 字段建议
27
27
 
@@ -63,26 +63,29 @@
63
63
 
64
64
  ## SDK 缓存模型
65
65
 
66
- 每个远程 AID 在内存和 SQLite 表中都维护一条缓存记录。内存记录与 SQLite 表记录字段语义一致,SQLite 用于 SDK 重启或内存 miss 时按需加载。
66
+ 每个远程 AID 在内存和本地持久化记录中都维护一条 agent.md 状态。Python / TypeScript / Go 的持久化记录是 `{aun_path}/AIDs/{aid}/agentmd.json`;浏览器 JavaScript 是 IndexedDB 中的 `{aid}/agentmd.json` logical key。SDK 启动或内存 miss 时按需加载该记录。
67
67
 
68
68
  | 字段 | 含义 |
69
69
  | --- | --- |
70
70
  | `aid` | 远程 AID |
71
- | `content` | 本地缓存的完整 `agent.md` 内容,可为空 |
72
- | `local_etag` | 当前 `content` 对应的 ETag,只能由 GET 200/304 确认 |
73
- | `remote_etag` | 从消息信封或 RPC `_meta` 观察到的远端云端 ETag |
74
- | `last_modified` | GET 响应的 `Last-Modified` |
75
- | `fetched_at` | 最近一次成功确认内容的本机时间 |
76
- | `observed_at` | 最近一次观察到远端 ETag 的本机时间 |
77
- | `stale` | `remote_etag` 与 `local_etag` 不一致,或有远端 ETag 但无内容 |
78
- | `verify_status` | 最近一次 `verify_agent_md` 结果:`verified` / `unsigned` / `invalid` |
71
+ | `content` | 本地缓存的完整 `agent.md` 内容,可为空 |
72
+ | `local_etag` | 当前 `content` 对应的 ETag,由成功 GET 200 内容确认;304 复用本地内容时沿用原值 |
73
+ | `remote_etag` | 从消息信封或 RPC `_meta` 观察到的远端云端 ETag |
74
+ | `last_modified` | GET 响应的 `Last-Modified` |
75
+ | `fetched_at` | 最近一次成功确认内容的本机时间 |
76
+ | `checked_at` | 最近一次 HEAD / GET 确认远端状态的本机时间 |
77
+ | `observed_at` | 最近一次观察到远端 ETag 的本机时间 |
78
+ | `remote_status` | `found` / `missing` / `error` |
79
+ | `verify_status` | 最近一次 agent.md 验签结果:`ok` / `unsigned` / `invalid` 等 |
80
+ | `verify_error` | 最近一次验签失败原因 |
81
+ | `last_error` | 最近一次网络或 HTTP 错误 |
79
82
 
80
83
  状态规则:
81
84
 
82
85
  - 收到远端 ETag 时,只更新 `remote_etag` 和 `observed_at`。
83
86
  - 只有下载到内容并完成验签后,才能更新 `content`、`local_etag`、`last_modified`、`fetched_at`。
84
- - `remote_etag == local_etag` 时,`stale=false`。
85
- - `remote_etag != local_etag` 或 `content` 为空时,`stale=true`。
87
+ - `remote_etag == local_etag` 时视为同步。
88
+ - `remote_etag != local_etag` 或 `content` 为空时视为需要更新;该状态可由字段推导,不要求单独存储 `stale` 字段。
86
89
  - `verify_status=invalid` 时内容可以缓存但应用层应能看到无效状态;是否拒绝展示由上层策略决定。
87
90
 
88
91
  ## 时序图
@@ -107,7 +110,7 @@ sequenceDiagram
107
110
  GW->>NS: HEAD https://B/agent.md<br/>取 to ETag(缓存命中则不请求)
108
111
  NS-->>GW: ETag(B)
109
112
  GW-->>A: RPC response + _meta.agent_md_etags.to
110
- A->>A: observeRemoteAgentMdEtag(B, etag)<br/>更新内存 + SQLite remote_etag
113
+ A->>A: observeRemoteAgentMdEtag(B, etag)<br/>更新内存 + agentmd.json/IndexedDB remote_etag
111
114
  ```
112
115
 
113
116
  ### 接收消息时,接收端获得 from 的 agent.md ETag
@@ -127,11 +130,11 @@ sequenceDiagram
127
130
  alt 本地 local_etag == remote_etag
128
131
  Cache-->>B: 只刷新 observed_at,不下载
129
132
  else 本地无内容或 ETag 不一致
130
- Cache->>Cache: 标记 stale,按需或后台拉取
131
- B->>NS: GET https://A/agent.md<br/>If-None-Match=local_etag
132
- NS-->>B: 200 content + ETag 304
133
+ Cache->>Cache: 标记需要更新,按需或后台拉取
134
+ B->>NS: GET https://A/agent.md<br/>不带条件请求头
135
+ NS-->>B: 200 content + ETag,或异常 304/404/error
133
136
  B->>B: verify_agent_md(content, aid=A)
134
- B->>Cache: 写内存 + SQLite
137
+ B->>Cache: 写内存 + agentmd.json/IndexedDB
135
138
  end
136
139
  ```
137
140
 
@@ -142,25 +145,25 @@ sequenceDiagram
142
145
  participant App
143
146
  participant SDK
144
147
  participant Mem as Memory Cache
145
- participant SQL as SQLite
148
+ participant Store as agentmd.json / IndexedDB
146
149
  participant NS as NameService
147
150
 
148
- App->>SDK: fetchAgentMd(A) / getRemoteAgentMd(A)
151
+ App->>SDK: downloadAgentMd(A)
149
152
  SDK->>Mem: 查 A
150
153
  alt 内存有可用 content
151
154
  Mem-->>SDK: content, local_etag
152
155
  else 内存缺失
153
- SDK->>SQL: load remote_agent_md_cache where aid=A
154
- SQL-->>SDK: content/remote_etag/local_etag/last_modified
156
+ SDK->>Store: load {aid}/agentmd.json
157
+ Store-->>SDK: content/remote_etag/local_etag/last_modified
155
158
  SDK->>Mem: 回填内存
156
159
  end
157
160
 
158
161
  alt 内容缺失或 remote_etag != local_etag
159
- SDK->>NS: GET /agent.md<br/>If-None-Match=local_etag
160
- NS-->>SDK: 200/304/404/error
161
- SDK->>SDK: 200 时验签;304 时复用旧 content
162
+ SDK->>NS: GET /agent.md<br/>不带条件请求头
163
+ NS-->>SDK: 200/304/404/error
164
+ SDK->>SDK: 200 时验签;304 时有本地 content 则复用,无 content 则再无条件 GET 一次
162
165
  SDK->>Mem: upsert
163
- SDK->>SQL: upsert
166
+ SDK->>Store: upsert agent.md + agentmd.json
164
167
  end
165
168
 
166
169
  SDK-->>App: agent.md content + signature + sync 状态
@@ -251,67 +254,53 @@ observe_remote_agent_md_etag(aid, etag, source)
251
254
 
252
255
  - aid 或 etag 为空时忽略。
253
256
  - etag 与当前 `remote_etag` 相同:只刷新 `observed_at`。
254
- - etag 变化:更新 `remote_etag`、`observed_at`,并根据 `local_etag` 设置 `stale`。
255
- - 变更需要同时写入内存和 SQLite
257
+ - etag 变化:更新 `remote_etag`、`observed_at`,并根据 `local_etag` 推导是否需要更新。
258
+ - 变更需要同时写入内存和 agentmd.json / IndexedDB
256
259
 
257
260
  ### 按需下载
258
261
 
259
- 当应用调用 `fetchAgentMd(aid)` 或 SDK 需要展示远程 agent 信息时:
260
-
261
- - 先查内存,miss 时查 SQLite 表。
262
- - 如果 `content` 存在且 `local_etag == remote_etag`,可直接返回缓存。
263
- - 如果 `content` 缺失或 stale,则发起 GET。
264
- - GET 时优先带 `If-None-Match=local_etag`,其次带 `If-Modified-Since=last_modified`。
265
- - 200:验签,更新内容和 `local_etag`。
266
- - 304:只有本地已有 content 时才能复用;如果本地没有 content 却收到 304,应清空条件头重试一次 GET。
267
- - 404:标记远端未发布 `agent.md`,不要删除已有内容,除非产品要求严格同步。
268
- - 网络错误:保留旧内容,记录 `fetch_error` 或更新失败时间。
269
-
270
- ### SQLite 持久化
271
-
272
- 新增结构化表 `remote_agent_md_cache`,每个远程 AID 一行:
273
-
274
- | | 类型 |
275
- | --- | --- |
276
- | `aid` | TEXT PRIMARY KEY |
277
- | `content` | TEXT NOT NULL DEFAULT '' |
278
- | `local_etag` | TEXT NOT NULL DEFAULT '' |
279
- | `remote_etag` | TEXT NOT NULL DEFAULT '' |
280
- | `last_modified` | TEXT NOT NULL DEFAULT '' |
281
- | `fetched_at` | INTEGER NOT NULL DEFAULT 0 |
282
- | `observed_at` | INTEGER NOT NULL DEFAULT 0 |
283
- | `verify_status` | TEXT NOT NULL DEFAULT '' |
284
- | `verify_error` | TEXT NOT NULL DEFAULT '' |
285
- | `updated_at` | INTEGER NOT NULL DEFAULT 0 |
286
-
287
- 建议 SQL:
288
-
289
- ```sql
290
- CREATE TABLE IF NOT EXISTS remote_agent_md_cache (
291
- aid TEXT PRIMARY KEY,
292
- content TEXT NOT NULL DEFAULT '',
293
- local_etag TEXT NOT NULL DEFAULT '',
294
- remote_etag TEXT NOT NULL DEFAULT '',
295
- last_modified TEXT NOT NULL DEFAULT '',
296
- fetched_at INTEGER NOT NULL DEFAULT 0,
297
- observed_at INTEGER NOT NULL DEFAULT 0,
298
- verify_status TEXT NOT NULL DEFAULT '',
299
- verify_error TEXT NOT NULL DEFAULT '',
300
- updated_at INTEGER NOT NULL DEFAULT 0
301
- );
302
-
303
- CREATE INDEX IF NOT EXISTS idx_remote_agent_md_cache_observed_at
304
- ON remote_agent_md_cache(observed_at);
305
- ```
306
-
307
- 五个 SDK 应保持字段语义一致。浏览器 JS 可落 IndexedDB;Node TS、Python、Go、C++ 落各自现有本地存储。
262
+ 当应用调用 `downloadAgentMd(aid)` 或 SDK 需要展示远程 agent 信息时:
263
+
264
+ - 可先查内存,miss 时查 agentmd.json / IndexedDB,用于展示本地已有状态。
265
+ - `downloadAgentMd(aid)` 的远端下载请求一律发起无条件 GET,不用本地 ETag 决定请求头。
266
+ - GET 请求不得发送 `If-None-Match` / `If-Modified-Since`。
267
+ - 200:验签,更新内容和 `local_etag`。
268
+ - 304:本地已有 content 时复用该 content;本地没有 content 时再发起一次无条件 GET。第二次仍非 2xx 时按错误返回。
269
+ - 404:标记远端未发布 `agent.md`,不要删除已有内容,除非产品要求严格同步。
270
+ - 网络错误:保留旧内容,记录 `fetch_error` 或更新失败时间。
271
+
272
+ ### 本地文件 / 浏览器持久化
273
+
274
+ agent.md 不写入 SQLite。当前 SDK 使用以下持久化位置:
275
+
276
+ | SDK | 正文 | 元数据 |
277
+ | --- | --- | --- |
278
+ | Python | `{aun_path}/AIDs/{aid}/agent.md` | `{aun_path}/AIDs/{aid}/agentmd.json` |
279
+ | TypeScript / Node | `{aun_path}/AIDs/{aid}/agent.md` | `{aun_path}/AIDs/{aid}/agentmd.json` |
280
+ | Go | `{aun_path}/AIDs/{aid}/agent.md` | `{aun_path}/AIDs/{aid}/agentmd.json` |
281
+ | JavaScript / 浏览器 | IndexedDB logical key `{root}/{aid}/agent.md` | IndexedDB logical key `{root}/{aid}/agentmd.json` |
282
+
283
+ `agentmd.json` 至少承载以下语义字段:
284
+
285
+ | 字段 | 说明 |
286
+ | --- | --- |
287
+ | `aid` | AID |
288
+ | `content` | 正文副本;文件系统 SDK 也会单独写 `agent.md` |
289
+ | `local_etag` / `remote_etag` | 本地内容版本 / 远端观察版本 |
290
+ | `last_modified` | 远端 Last-Modified |
291
+ | `fetched_at` / `checked_at` / `observed_at` / `updated_at` | 本机时间戳 |
292
+ | `remote_status` | `found` / `missing` / `error` |
293
+ | `verify_status` / `verify_error` | 最近一次验签状态 |
294
+ | `last_error` | 最近一次错误 |
295
+
296
+ 四个已实现 SDK 应保持字段语义一致。旧 `agent_md_cache` / `remote_agent_md_cache` SQLite 表不再作为 agent.md 缓存来源;迁移逻辑可清理旧表,但不得把新 agent.md 写回 SQLite。
308
297
 
309
298
  ## 异常与竞态处理
310
299
 
311
300
  - 多个消息同时观察同一 AID 的新 ETag:按 ETag 值幂等 upsert。
312
301
  - 多个协程同时触发同一 AID 下载:需要 per-AID in-flight 去重。
313
- - 观察到 ETag A 后开始下载,期间又观察到 ETag B:下载完成时只更新 `local_etag=A`,随后仍保持 stale,下一轮继续拉 B。
314
- - 304 但本地 content 缺失:不能返回空内容,必须无条件 GET 重试。
302
+ - 观察到 ETag A 后开始下载,期间又观察到 ETag B:下载完成时只更新 `local_etag=A`,随后仍可由 `remote_etag != local_etag` 推导为需要更新,下一轮继续拉 B。
303
+ - 304 但本地 content 缺失:不能返回空内容,必须再无条件 GET 一次。
315
304
  - 信封里的 ETag 不参与 AAD,不作为安全声明;安全性仍依赖 `agent.md` 签名和证书校验。
316
305
  - HEAD/GET 超时不影响 message send 和 message pull。
317
306
  - 跨域场景中,目标域 Message Service 注入 sender ETag 时可能需要跨域 HEAD;失败时允许缺字段。
@@ -320,9 +309,9 @@ ON remote_agent_md_cache(observed_at);
320
309
 
321
310
  - 发送方收到 `message.send` 响应后,能把 `to` 的 ETag 写入本地缓存 `remote_etag`。
322
311
  - 接收方 `message.v2.pull` 后,能从 `envelope.agent_md.sender` 写入 `from` 的 `remote_etag`。
323
- - ETag 变化但内容未下载时,缓存状态为 stale。
324
- - 本地 SQLite 有缓存、内存为空时,SDK 能按需加载。
325
- - 304 且本地有内容时复用内容;304 但本地无内容时强制重拉。
312
+ - ETag 变化但内容未下载时,可由 `remote_etag != local_etag` 推导为需要更新。
313
+ - 本地文件 / IndexedDB 有缓存、内存为空时,SDK 能按需加载。
314
+ - 304 且本地有内容时复用内容;304 但本地无内容时再无条件 GET 一次。
326
315
  - `agent.md` 上传后,Gateway 缓存失效,后续消息能看到新 ETag。
327
316
  - HEAD/GET 404、超时、网络错误不影响消息收发主链路。
328
- - Python / TS / JS / Go / C++ 五个 SDK 对 `remote_etag`、`local_etag`、`content`、`stale` 语义一致。
317
+ - Python / TS / JS / Go 四个 SDK 对 `remote_etag`、`local_etag`、`content`、`remote_status`、`verify_status` 语义一致。
@@ -1,6 +1,6 @@
1
1
  # AUN SDK - 快速开始
2
2
 
3
- **版本**: 0.4.4+ | **Python**: >= 3.11
3
+ **版本**: 0.4.5+ | **Python**: >= 3.11
4
4
 
5
5
  ---
6
6
 
@@ -26,7 +26,7 @@ pip install fastaun
26
26
 
27
27
  - `AUNClient()`:无身份客户端,状态为 `no_identity`,随后用 `load_identity(AID对象)` 加载身份。
28
28
  - `AUNClient(aid)`:带身份客户端,`aid` 必须是 `AIDStore.load()` 返回的 AID 对象,状态为 `standby`。
29
- - TS/JS/Go 同构:只允许 `options` `AID对象 + options`;字符串 AID、把 aid 放进 options、旧 `(config, debug)` 都不是公开入口。
29
+ - TS/JS/Go 同构:只允许无参或 `AID` 对象;字符串 AID、把 aid 放进 options、旧 `(config, debug)` / `(aid, options)` 都不是公开入口。
30
30
 
31
31
  ---
32
32
 
@@ -67,7 +67,7 @@ async def load_or_register(store: AIDStore, aid: str):
67
67
  async def create_client(aid: str) -> AUNClient:
68
68
  store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")
69
69
  identity = await load_or_register(store, aid)
70
- client = AUNClient(identity, debug=True)
70
+ client = AUNClient(identity)
71
71
  await client.connect({"slot_id": "main", "auto_reconnect": True})
72
72
  return client
73
73
 
@@ -116,13 +116,14 @@ store = AIDStore(
116
116
  )
117
117
  ```
118
118
 
119
- `AUNClient` 只接收 AID 对象和连接级选项:
119
+ `AUNClient` 只接收可选 AID 对象。调试、TLS、根证书和默认 slot 等配置由 `AIDStore` 注入到 AID 对象,再由 client 继承;`protected_headers` 通过 setter 配置:
120
120
 
121
121
  ```python
122
- identity = store.load("alice.agentid.pub")["data"]["aid"]
123
- client = AUNClient(identity, debug=True, protected_headers={"sdk": "python"})
124
- await client.connect({"slot_id": "main", "connection_kind": "long"})
125
- ```
122
+ identity = store.load("alice.agentid.pub")["data"]["aid"]
123
+ client = AUNClient(identity)
124
+ client.set_protected_headers({"sdk": "python"})
125
+ await client.connect({"slot_id": "main", "connection_kind": "long"})
126
+ ```
126
127
 
127
128
  `verify_ssl` 在 `AIDStore` 构造时配置,不在 `AUNClient` 中配置。自动模式下 SDK 根据环境变量决定:
128
129
 
@@ -165,17 +166,17 @@ SDK 使用 `{aun_path}/AIDs/{aid}/` 存储每个 AID 的专属数据:
165
166
  TypeScript / Node:
166
167
 
167
168
  ```ts
168
- const store = new AIDStore({ aunPath: "~/.aun/myapp", encryptionSeed: "" });
169
- const loaded = store.load("alice.agentid.pub");
170
- const client = new AUNClient(loaded.data!.aid, { debug: true });
169
+ const store = new AIDStore({ aunPath: "~/.aun/myapp", encryptionSeed: "" });
170
+ const loaded = store.load("alice.agentid.pub");
171
+ const client = new AUNClient(loaded.data!.aid);
171
172
  ```
172
173
 
173
174
  JavaScript / 浏览器:
174
175
 
175
176
  ```js
176
- const store = new AIDStore({ aunPath: "browser-demo", encryptionSeed: "" });
177
- const loaded = await store.load("alice.agentid.pub");
178
- const client = new AUNClient(loaded.data.aid, { debug: true });
177
+ const store = new AIDStore({ aunPath: "browser-demo", encryptionSeed: "" });
178
+ const loaded = await store.load("alice.agentid.pub");
179
+ const client = new AUNClient(loaded.data.aid);
179
180
  ```
180
181
 
181
182
  Go:
@@ -195,7 +196,7 @@ client := aun.NewAUNClient(aid.Data.AID)
195
196
 
196
197
  1. 创建 `AIDStore`。
197
198
  2. `store.load(aid)` 加载本地 AID;本地不存在时调用 `store.register(aid)` 后再次加载。
198
- 3. 用 AID 对象构造 `AUNClient(aid, ...)`,或先 `AUNClient()` 再 `load_identity(aid)`。
199
+ 3. 用 AID 对象构造 `AUNClient(aid)`,或先 `AUNClient()` 再 `load_identity(aid)`。
199
200
  4. 先注册事件处理器,再调用 `connect(options)`。
200
201
  5. 通过 `call(method, params)` 执行业务 RPC。
201
202
  6. 通过 `close()` 释放连接和后台任务。
@@ -73,9 +73,9 @@ sequenceDiagram
73
73
 
74
74
  - `protocol.min/max` 在 `auth.connect` 阶段完成 Gateway 会话版本协商;详细规则见协议文档 `03-Gateway-连接模式.md`。
75
75
  - `device.id` 是设备级稳定标识,Python SDK 默认从 `~/.aun/.device_id` 读取。
76
- - `client.slot_id` 由应用层显式传入,用于区分同设备上的多个实例槽位。
76
+ - `client.slot_id` 由应用层显式传入,用于区分同设备上的多个实例槽位。SDK 允许 `/`、`:`、空格作为隔离键分隔符,例如 `evolclaw cli`、`evolclaw/cli`、`evolclaw:cli` 的隔离键都是 `evolclaw`。
77
77
  - `delivery_mode` 决定该 AID 当前连接的投递语义;同一 AID 的所有在线连接必须保持一致。
78
- - `options.kind` 声明连接类型:`"long"`(默认)= 长连接,承担服务端推送 / 事件订阅;`"short"` = 短连接,仅用于发送 RPC 并等待响应即断开。同 `(aid, device.id, client.slot_id)` 槽位下,长连接最多 1 条,短连接最多 10 条;短连接不会顶掉长连接。
78
+ - `options.kind` 声明连接类型:`"long"`(默认)= 长连接,承担服务端推送 / 事件订阅;`"short"` = 短连接,仅用于发送 RPC 并等待响应即断开。同 `(aid, device.id, slotIsolationKey(client.slot_id))` 隔离槽下,长连接最多 1 条,短连接最多 10 条;短连接不会顶掉长连接。
79
79
  - `options.short_ttl_ms` 仅在 `kind="short"` 时有效,可选;服务端兜底超时后主动关闭短连接,防止占名额。
80
80
  - `capabilities` 是客户端能力声明;`hello-ok.result.capabilities` 是服务端能力公告,不是双方能力交集。
81
81
 
@@ -36,11 +36,28 @@ assert me.is_private_key_valid()
36
36
  | `AID` | 身份值对象,负责签名、验签、agent.md 签验 | 否 |
37
37
  | `AUNClient` | 会话对象,负责认证、连接、重连、事件和 RPC | 是 |
38
38
 
39
- `AUNClient` 不再通过配置字典持有某个字符串 AID;它只接收已加载并校验过私钥的 AID 对象。
40
-
41
- ---
42
-
43
- ## 连接状态机
39
+ `AUNClient` 不再通过配置字典持有某个字符串 AID;它只接收已加载并校验过私钥的 AID 对象。
40
+
41
+ ---
42
+
43
+ ## device_id 与 slot_id
44
+
45
+ `device_id` 是设备级稳定标识,默认写在 `{aun_path}/.device_id`,用于 token、实例状态、V2 设备密钥和消息游标的一级隔离。它是单段安全 token,只允许字母、数字、`.`、`_`、`-`。
46
+
47
+ `slot_id` 是同一设备下的连接/消费槽位,允许用 `/`、`:`、空格表达共享隔离键。隔离键取第一个分隔符前的部分:
48
+
49
+ | slot_id | slotIsolationKey |
50
+ |---------|------------------|
51
+ | `evolclaw daemon` | `evolclaw` |
52
+ | `evolclaw cli` | `evolclaw` |
53
+ | `evolclaw/netcheck` | `evolclaw` |
54
+ | `evolclaw-daemon` | `evolclaw-daemon` |
55
+
56
+ SDK 在 `message.pull` / `message.ack` 中自动注入当前 `device_id` / `slot_id`,并按隔离键校验显式传入的 `slot_id`。因此共享消费槽位时应使用 `/`、`:` 或空格作为分隔符。
57
+
58
+ ---
59
+
60
+ ## 连接状态机
44
61
 
45
62
  ```mermaid
46
63
  stateDiagram-v2
@@ -16,9 +16,9 @@ if not loaded["ok"]:
16
16
  raise RuntimeError(registered["error"]["message"])
17
17
  loaded = store.load(aid)
18
18
 
19
- me = loaded["data"]["aid"]
20
- client = AUNClient(me, debug=True)
21
- await client.connect({"slot_id": "main", "auto_reconnect": True})
19
+ me = loaded["data"]["aid"]
20
+ client = AUNClient(me)
21
+ await client.connect({"slot_id": "main", "auto_reconnect": True})
22
22
  ```
23
23
 
24
24
  关键约束:
@@ -62,9 +62,9 @@ store = AIDStore(
62
62
  | `register(aid)` | 注册新 AID,返回 Result |
63
63
  | `list()` | 列出本地身份 |
64
64
  | `exists(aid)` | HEAD PKI 端点,判断 AID 是否已注册 |
65
- | `resolve(aid, opts=None)` | 拉取并缓存对端证书和 agent.md |
66
- | `fetch_agent_md(aid)` | 下载并验签对端 agent.md |
67
- | `check_agent_md(aid, ttl_days=1)` | 检查本地缓存与远端 agent.md 状态 |
65
+ | `resolve(aid, opts=None)` | 拉取并缓存对端证书;默认同时下载并验签 agent.md,可传 `skip_agent_md=True` 跳过 |
66
+ | `download_agent_md(aid)` | 下载并验签对端 agent.md |
67
+ | `check_agent_md(aid, ttl_days=1)` | 检查本地缓存与远端 agent.md 状态 |
68
68
  | `diagnose(aid)` | 本地和远端一致性诊断 |
69
69
  | `renew_cert(aid)` / `rekey(aid)` | 证书续签和换钥,成功后重新 `load()` |
70
70
 
@@ -125,7 +125,7 @@ await client.connect({
125
125
 
126
126
  | 选项 | 说明 |
127
127
  |------|------|
128
- | `slot_id` | 同一设备内的实例槽位 |
128
+ | `slot_id` | 同一设备内的实例槽位;允许 `/`、`:`、空格作为共享隔离键分隔符 |
129
129
  | `connection_kind` | `"long"` 或 `"short"` |
130
130
  | `short_ttl_ms` | 短连接服务端兜底超时 |
131
131
  | `delivery_mode` | 连接级投递语义 |
@@ -141,7 +141,7 @@ await client.connect({
141
141
 
142
142
  ## 长短连接共存
143
143
 
144
- 同一 `(aid, device_id, slot_id)` 槽位下允许 1 条长连接 + 最多 10 条短连接。
144
+ 同一 `(aid, device_id, slotIsolationKey(slot_id))` 隔离槽下允许 1 条长连接 + 最多 10 条短连接。`slot_id` 的第一个 `/`、`:` 或空格之前的部分是共享隔离键,因此 `evolclaw daemon`、`evolclaw cli`、`evolclaw/netcheck` 会共享 `evolclaw` 隔离槽。
145
145
 
146
146
  长连接:
147
147
 
@@ -199,27 +199,43 @@ print(client.can_connect, client.can_send, client.is_online)
199
199
 
200
200
  ---
201
201
 
202
- ## Agent Web / agent.md
203
-
204
- 发布自己的 agent.md:
205
-
206
- ```python
207
- await client.publish_agent_md(content)
208
- ```
209
-
210
- 解析对端并验签 agent.md:
202
+ ## Agent Web / agent.md
203
+
204
+ 发布自己的 agent.md:
205
+
206
+ ```python
207
+ await client.upload_agent_md(content)
208
+ ```
209
+
210
+ 解析对端并验签 agent.md:
211
211
 
212
212
  ```python
213
213
  resolved = await store.resolve("bob.agentid.pub")
214
- if resolved["ok"]:
215
- print(resolved["data"]["agent_md"]["signature"]["status"])
216
- ```
217
-
218
- 只检查远端是否存在:
219
-
220
- ```python
221
- head = await store.head_agent_md("bob.agentid.pub")
222
- ```
214
+ if resolved["ok"]:
215
+ print(resolved["data"]["agent_md"]["verification"]["status"])
216
+ ```
217
+
218
+ 只下载对端 agent.md:
219
+
220
+ ```python
221
+ downloaded = await store.download_agent_md("bob.agentid.pub")
222
+ ```
223
+
224
+ 只检查本地缓存与远端状态:
225
+
226
+ ```python
227
+ state = await store.check_agent_md("bob.agentid.pub", ttl_days=1)
228
+ ```
229
+
230
+ 当前公开入口分工固定:
231
+
232
+ | 主体 | 公开能力 |
233
+ |------|----------|
234
+ | `AUNClient` | `upload_agent_md(content=None)`:读取/签名/上传当前 AID 的 agent.md |
235
+ | `AIDStore` | `download_agent_md(aid)`、`check_agent_md(aid, ttl_days=1)`、`resolve(aid, opts)` |
236
+ | `AID` | `sign_agent_md(content)`、`verify_agent_md(content)` 低层签验能力 |
237
+
238
+ 本地落盘位置由 SDK 管理。Python / TypeScript / Go 写入 `{aun_path}/AIDs/{aid}/agent.md` 和同目录 `agentmd.json`;浏览器 JavaScript 写入 IndexedDB 的等价 logical key,存储不可用时退化为内存缓存。agent.md 不写入 SQLite,也不再使用旧 `{aun_path}/AgentMDs` 目录。
223
239
 
224
240
  ---
225
241
 
@@ -74,7 +74,7 @@ headers = (
74
74
  ProtectedHeaders()
75
75
  .set("device_id", "dev-123")
76
76
  .set("slot_id", "desktop")
77
- .set("sdk_version", "0.4.4")
77
+ .set("sdk_version", "0.4.5")
78
78
  .set("app_name", "my-agent")
79
79
  )
80
80
 
@@ -596,7 +596,7 @@ class MySecretStore:
596
596
  client = AUNClient(aid)
597
597
  ```
598
598
 
599
- `AUNClient` 构造函数只接收可选 AID 对象和会话选项。`SecretStore` / `KeyStore` / `SQLiteBackup` 属于 SDK 内部基础设施,不作为应用层构造参数暴露。
599
+ `AUNClient` 构造函数只接收可选 AID 对象。`SecretStore` / `KeyStore` / `SQLiteBackup` 属于 SDK 内部基础设施,不作为应用层构造参数暴露。
600
600
 
601
601
  ---
602
602