@agentunion/fastaun-browser 0.5.19 → 0.5.21
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 +176 -78
- package/_packed_docs/CHANGELOG.md +176 -78
- package/_packed_docs/INDEX.md +288 -269
- package/_packed_docs/KITE_DOCS_GUIDE.md +101 -95
- package/_packed_docs/agent.md/SCHEMA.md +7 -7
- package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/344/270/216/346/215/242owner/347/274/226/346/216/222/346/226/271/346/241/210.md +530 -0
- package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/345/256/214/346/225/264/350/256/276/350/256/241/344/270/216/345/256/236/346/226/275/350/256/241/345/210/222.md +685 -0
- package/_packed_docs/agent.md/working/agent.md-schema/344/270/216/347/255/276/345/217/221/351/252/214/347/255/276/346/265/201/347/250/213/346/276/204/346/270/205.md +349 -0
- package/_packed_docs/agent.md/working//346/234/254/345/234/260Docker/346/265/213/350/257/225Bug/346/270/205/345/215/225.md +40 -0
- package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +11 -11
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +372 -331
- package/_packed_docs/protocol/08-AUN-E2EE.md +17 -12
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +676 -676
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +8 -12
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +445 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +666 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
- package/_packed_docs/protocol/agent.md/SCHEMA.md +1 -1
- package/_packed_docs/sdk/0.5.21-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +368 -0
- package/_packed_docs/sdk/0.5.21-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +350 -0
- package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +1 -1
- package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +5 -1
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +64 -64
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +70 -63
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +43 -40
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +179 -19
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +50 -49
- package/_packed_docs/sdk/09-group-rpc-manual.md +261 -254
- package/_packed_docs/sdk/09-message-rpc-manual.md +253 -160
- package/_packed_docs/sdk/09-storage-rpc-manual.md +18 -26
- package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +71 -0
- package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +88 -0
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +105 -92
- package/_packed_docs/sdk/INDEX.md +197 -167
- package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +930 -0
- package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
- package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +363 -0
- package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +553 -0
- package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +708 -0
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +480 -0
- package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
- package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +173 -0
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +211 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/345/256/236/347/216/260/347/247/273/346/244/215/346/214/207/345/215/227.md +331 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +207 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/344/273/243/347/240/201/345/256/241/346/237/245/346/212/245/345/221/212.md +252 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/345/256/236/346/226/275/350/256/241/345/210/222.md +156 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/346/226/271/346/241/210.md +273 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/350/257/246/347/273/206/350/256/276/350/256/241.md +211 -0
- package/dist/agent-md-schema.d.ts +16 -4
- package/dist/agent-md-schema.d.ts.map +1 -1
- package/dist/agent-md-schema.js +65 -30
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +35 -3
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +384 -150
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +59 -0
- package/dist/aid-store.d.ts.map +1 -1
- package/dist/aid-store.js +202 -16
- package/dist/aid-store.js.map +1 -1
- package/dist/aid.d.ts +4 -1
- package/dist/aid.d.ts.map +1 -1
- package/dist/aid.js +24 -42
- package/dist/aid.js.map +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +89 -18
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +6410 -1848
- package/dist/cert-utils.d.ts +50 -1
- package/dist/cert-utils.d.ts.map +1 -1
- package/dist/cert-utils.js +123 -56
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/delivery.d.ts +108 -16
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +1411 -184
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +4 -1
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +203 -117
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +22 -3
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +1312 -684
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +23 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +419 -101
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +8 -6
- package/dist/crypto.js.map +1 -1
- package/dist/events.d.ts +24 -3
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +171 -29
- package/dist/events.js.map +1 -1
- package/dist/facades.d.ts +42 -1
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +368 -12
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/keystore/index.d.ts +14 -1
- package/dist/keystore/index.d.ts.map +1 -1
- package/dist/keystore/indexeddb-identity-store.d.ts +4 -0
- package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-identity-store.js +30 -13
- package/dist/keystore/indexeddb-identity-store.js.map +1 -1
- package/dist/keystore/indexeddb-shared.d.ts +19 -2
- package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.js +193 -6
- package/dist/keystore/indexeddb-shared.js.map +1 -1
- package/dist/keystore/indexeddb-token-store.d.ts +15 -2
- package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-token-store.js +308 -27
- package/dist/keystore/indexeddb-token-store.js.map +1 -1
- package/dist/org-protocol.d.ts +45 -0
- package/dist/org-protocol.d.ts.map +1 -1
- package/dist/org-protocol.js +827 -21
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.d.ts +43 -9
- package/dist/ownership-v21.d.ts.map +1 -1
- package/dist/ownership-v21.js +183 -81
- package/dist/ownership-v21.js.map +1 -1
- package/dist/ownership-workflow.d.ts +36 -1
- package/dist/ownership-workflow.d.ts.map +1 -1
- package/dist/ownership-workflow.js +610 -89
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/seq-tracker.d.ts +2 -0
- package/dist/seq-tracker.d.ts.map +1 -1
- package/dist/seq-tracker.js +3 -2
- package/dist/seq-tracker.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +61 -3
- package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
- package/dist/tools/cross-sdk-agent.js +524 -45
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +4 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +64 -30
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Ownership 协议定义 3.0
|
|
2
|
+
|
|
3
|
+
本文综合[原 Ownership 协议](Ownership协议定义.md)、[Ownership 2.0](Ownership协议定义2.0.md)与 Git 提交 `1f03bf2d` 中的 0.5.18 owner relation 实现,定义新的设计契约,与历史协议并存。SDK 场景见[Ownership SDK编排指南](../sdk/Ownership-SDK编排指南.md)。本文不表示现有服务或 SDK 已实现 3.0,也不直接修改现有 [agent.md Schema](../agent.md/SCHEMA.md)。
|
|
4
|
+
|
|
5
|
+
关系权威决定谁是当前 owner;双方签名文件提供公开声明和审计证据。绑定、解绑、转移均通过可恢复 operation 完成,文档发布与可选托管分别推进。
|
|
6
|
+
|
|
7
|
+
## 1. 核心概念与安全边界
|
|
8
|
+
|
|
9
|
+
| 概念 | 定义 |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `sub_aid` | 被管理的完整小写 AID。 |
|
|
12
|
+
| `owner_aid` | 当前具有该关系管理授权的完整小写 AID;一条 active 关系只有一个当前 owner。 |
|
|
13
|
+
| 关系权威 | `sub_aid` 所属 issuer 的 Auth/Relation 服务。跨 issuer 的 owner 也在这里提交授权,不产生第二份关系权威。 |
|
|
14
|
+
| `relation_id` | sub_aid 关系记录的稳定标识,小写 UUID v4;解绑、重绑和转移均不更换。 |
|
|
15
|
+
| `relation_version` | 关系记录的单调递增整数;初始为 `0`,每次有效提交加一,解绑后仍保留,不重置。 |
|
|
16
|
+
| `operation_id` | 一次操作的唯一标识,用于授权、幂等、查询和崩溃恢复。 |
|
|
17
|
+
| 声明文档 | sub_aid 的 `agent.md` 与 owner_aid 的 `owner.md`,由各自独立签名、上传。 |
|
|
18
|
+
|
|
19
|
+
必须遵守:
|
|
20
|
+
|
|
21
|
+
1. 文件更新、删除、证书更新或 SDK 本地状态都不能单独改变关系权威中的 owner。
|
|
22
|
+
2. 解绑必须由当前 owner 授权;转移必须由当前 owner、sub_aid、新 owner 共同授权。sub_aid 不能通过删文件、先解绑、重注册或改类型绕过当前 owner。
|
|
23
|
+
3. 每次提交必须比较当前状态、当前 owner 和 `expected_relation_version`;重试同一 operation 不重复递增版本。
|
|
24
|
+
4. 所有身份以服务端确认的认证上下文和对应 AID 的证书为准,拒绝客户端伪造 `_auth` 等内部身份字段。
|
|
25
|
+
5. 不代签、不代上传:双方只能签署、公开写入自己的文件。托管不能自动授予代签、代上传能力。
|
|
26
|
+
6. 降级只能减少功能,不能减少授权或版本检查。权威不可用时,不能以文件共识或缓存推断当前 owner。
|
|
27
|
+
|
|
28
|
+
本协议约束 AID 之间的授权关系,不能限制持有同一私钥的程序冒用该 AID。应用把可解密私钥交给 owner 时,已授予其该身份的实际控制能力;移除 SDK 代签接口不能消除这一事实。
|
|
29
|
+
|
|
30
|
+
## 2. 权威关系与授权条件
|
|
31
|
+
|
|
32
|
+
关系记录至少包含 `relation_id`、`sub_aid`、`owner_aid`、`relation_version`、`state`、`last_operation_id` 和最近提交回执。`owner_aid` 在无 owner 时为 `null`。
|
|
33
|
+
|
|
34
|
+
| 权威状态 | 含义 |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| `unbound` | 没有当前 owner,可以建立绑定;仍保留关系标识和历史版本。 |
|
|
37
|
+
| `active` | 存在一个已授权的当前 owner。 |
|
|
38
|
+
|
|
39
|
+
等待、失败、过期、不可用是操作或查询状态,不覆盖当前权威关系。准备转移时旧关系仍为 active;准备解绑时也不提前清空 owner。
|
|
40
|
+
|
|
41
|
+
关系记录及解绑后的历史版本必须持久保留。存储读取、重启恢复或一致性校验失败时返回 `unavailable`,不能用空状态重新初始化为 unbound;只有权威确认的新身份或有效 release 才能处于 unbound。
|
|
42
|
+
|
|
43
|
+
| 操作 | 起始条件 | 必须授权 | 提交结果 |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| `bind` | `unbound`,匹配当前版本 | sub_aid + 拟绑定 owner | `active`,版本加一 |
|
|
46
|
+
| `transfer` | `active`,匹配当前 owner 与版本 | 当前 owner + sub_aid + 新 owner | `active`,直接替换 owner,版本加一 |
|
|
47
|
+
| `release` | `active`,匹配当前 owner 与版本 | 当前 owner | `unbound`,清空 owner,版本加一 |
|
|
48
|
+
|
|
49
|
+
sub_aid 可以发起解绑意向,但不能自行提交解绑。当前 owner 可以释放关系,不要求 sub_aid 在线;如果必须先隔离已外泄的身份凭据,则等待该安全步骤完成。转移直接从旧 owner 切换到新 owner,不经过可被抢绑的 unbound 窗口。
|
|
50
|
+
|
|
51
|
+
保留现有类型约束:human 不作为 sub_aid;只有 `type: agent` 支持 self-owner。self-owner 仍走同一权威记录和版本检查;外部 owner 不能被普通更新改成 self-owner。类型以可信身份记录为准,不能只信任上传的 frontmatter。管理授权只针对直接关系,不自动沿 owner 链继承。
|
|
52
|
+
|
|
53
|
+
## 3. 双方声明文档
|
|
54
|
+
|
|
55
|
+
### 3.1 声明 schema
|
|
56
|
+
|
|
57
|
+
两份文件采用相同的 `ownership.statement`:
|
|
58
|
+
|
|
59
|
+
| 字段 | 约束 |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| `version` | 固定为 `3`。 |
|
|
62
|
+
| `relation_id` | 关系权威分配的稳定标识。 |
|
|
63
|
+
| `relation_version` | 本份声明对应的已提交版本;准备文件使用 operation 的目标版本。 |
|
|
64
|
+
| `operation_id` | 建立该版本的 operation;普通正文更新不更换。 |
|
|
65
|
+
| `owner_aid`、`sub_aid` | 与该版本的权威关系一致。 |
|
|
66
|
+
| `declaration_id` | 本份声明的小写 UUID v4,双方可以不同。 |
|
|
67
|
+
| `declared_at` | Unix 秒正整数,处于被签名的正文中。 |
|
|
68
|
+
|
|
69
|
+
`agent.md` 保留已有身份字段与业务正文;出现 owner 时须同时包含 `owner` 和 `ownership.statement`,`owner` 等于声明中的 `owner_aid`,`aid` 等于 `sub_aid`。解绑提交后,sub_aid 自行移除这两个字段并重新签名上传。
|
|
70
|
+
|
|
71
|
+
owner 的声明存放于:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
owner_aid:/sub_aids/{sub_aid}/owner.md
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`owner.md` 是 YAML frontmatter、可选正文及尾部文件签名块,frontmatter 包含 `owner_aid`、`sub_aid` 和上述 `ownership.statement`。顶层 AID 必须与 statement 及路径一致。公开可读、可下载;只有 owner_aid 自己可以认证写入或删除,不开放公共写权限。
|
|
78
|
+
|
|
79
|
+
### 3.2 文件签名
|
|
80
|
+
|
|
81
|
+
ownership 字段不再独立签名,由整个文件的尾部签名保护;不增加 `signer_aid`。文件签署者由位置和证书所属 AID 确定:`agent.md` 是 sub_aid,`owner.md` 是 owner_aid。
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
<!-- AUN-SIGNATURE-OWNERSHIP-V2
|
|
85
|
+
cert_fingerprint: sha256:<64位hex>
|
|
86
|
+
public_key_fingerprint: sha256:<64位hex>
|
|
87
|
+
timestamp: <unix-seconds>
|
|
88
|
+
signature: <base64-der-signature>
|
|
89
|
+
-->
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
沿用 [agent.md 的文件签名格式](../agent.md/SCHEMA.md):ECDSA P-256/SHA-256,签名输入为尾部块之前的全部原始 UTF-8 字节,不规范化空白和换行。agent.md 兼容 `AUN-SIGNATURE`,也可使用 `AUN-SIGNATURE-AGENTMD-V2`;owner.md 使用 `AUN-SIGNATURE-OWNERSHIP-V2`。TAG 是文件载体标识,Ownership 版本由已签名的 `statement.version` 决定。
|
|
93
|
+
|
|
94
|
+
必须检查证书链、AID、精确指纹、算法及有效性,拒绝重复或歧义字段。尾部 `timestamp` 不在文件签名输入内,不能单独作为可信历史时间;审计以权威验收时间、文档摘要及提交回执共同取证。
|
|
95
|
+
|
|
96
|
+
### 3.3 准备证据与公开投影
|
|
97
|
+
|
|
98
|
+
- 提交前,各方生成目标版本的签名文件,分别提交给关系权威,作为 operation 的不可变证据快照;不覆盖当前公开文件。这是证据提交,不是 Name Service 或 Storage 的公开发布。
|
|
99
|
+
- bind 和 transfer 需要 sub_aid 的新 agent.md 及新 owner 的 owner.md;release 使用当前关系已保存的声明快照,不等待 sub_aid 生成无 owner 文档。
|
|
100
|
+
- 权威提交后,各方使用自己的身份,将对应文件发布到自己的服务。服务端核对当前关系及版本;普通 PUT 只能修改业务内容,不能新增、删除、替换 active 关系字段。
|
|
101
|
+
- 解绑后的字段清除使用 release 回执;转移后的新文件使用 transfer 回执。回执不是代上传凭证,上传者仍必须是文件所属 AID。
|
|
102
|
+
- 发布使用最新业务正文及 ETag 条件,可由文件所属 AID 保留已提交关系字段重新签名;新的公开文件不替换 operation 中已冻结的原始证据。
|
|
103
|
+
- 文件发布失败时,已提交关系保持稳定;缺失或旧版本文件只产生 `pending`、`missing` 或 `stale`,不得授予新关系的业务权限。迟到的旧版本上传、删除必须被拒绝或按版本条件忽略。
|
|
104
|
+
|
|
105
|
+
## 4. Operation 与签名授权
|
|
106
|
+
|
|
107
|
+
### 4.1 操作上下文
|
|
108
|
+
|
|
109
|
+
prepare 固定 `version=3`、`authority_issuer`、`action`、`operation_id`、`relation_id`、`sub_aid`、`old_owner_aid`、`new_owner_aid`、`expected_relation_version`、`target_relation_version`、`expires_at` 和 `idempotency_key`。bind 的 old owner 为 null;release 的 new owner 为 null。目标版本固定为当前版本加一。
|
|
110
|
+
|
|
111
|
+
准备完成后,上下文还固定 `document_hashes` 与 `security_generation`:前者包含 `sub_document_sha256`、`owner_document_sha256`,均为完整签名文件字节的 SHA-256,以64位小写hex表示;bind/transfer 使用目标声明,release 使用已保存的当前声明。后者为 `{credential_generation, custody_generation}`,均是权威确认的非负整数。没有托管时也不能由客户端伪造或跳过已存在的私钥外发记录。
|
|
112
|
+
|
|
113
|
+
操作有效期默认 7 天。幂等键按发起者、sub_aid 和 action 隔离;同键同参数返回同一 operation,同键不同参数返回 `idempotency_key_reuse`。prepare 仅接受 sub_aid 或当前 owner;新 owner 只能加入已创建的 operation,不能抢占别人的关系。
|
|
114
|
+
|
|
115
|
+
### 4.2 授权签名
|
|
116
|
+
|
|
117
|
+
operation 授权是控制面的签名同意,不是 ownership 字段的独立签名。每方确认 action、双方 AID、版本、证据摘要和有效期后签署权威返回的完整固定上下文:
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
UTF-8("AUN-OWNERSHIP-OPERATION-V3;") || JCS(operation_context)
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
JCS 使用 RFC 8785;本协议的版本、代际及时间为可精确表示的整数。签名算法与文件签名一致,封套包含 `cert_fingerprint` 和 `signature`;不设 `signer_aid`。
|
|
124
|
+
|
|
125
|
+
| 授权位置 | 预期签署者 |
|
|
126
|
+
| --- | --- |
|
|
127
|
+
| `sub_approval` | sub_aid |
|
|
128
|
+
| `owner_approval` | bind 的 new_owner_aid |
|
|
129
|
+
| `old_owner_approval` | transfer 或 release 的当前 old_owner_aid |
|
|
130
|
+
| `new_owner_approval` | transfer 的 new_owner_aid |
|
|
131
|
+
|
|
132
|
+
每方只能通过自己的认证上下文提交本端证据和 approval。新的 approval 与 bind/transfer 的目标签名证据,在验收和提交时检查 active signing 与撤销规则;release/transfer 引用的旧声明档案按原提交回执、精确文档摘要及原验收时间验证,不要求历史证书当前仍可签名,也不接受新造的回溯文件冒充档案。
|
|
133
|
+
|
|
134
|
+
同一份授权签名不能用于另一 operation、另一 issuer 或另一版本。上下文冻结后不得替换证据或授权;需要改内容时取消旧操作并重新准备。self-owner 中同一 AID 的有效同意可同时满足其重合角色。
|
|
135
|
+
|
|
136
|
+
### 4.3 稳定阶段
|
|
137
|
+
|
|
138
|
+
| 阶段 | 已持久化的事实 | 当前关系与恢复方式 |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| `prepared` | 操作参数、版本、期限;各准备任务的进度 | 原关系不变;继续本端证据准备和必要的密钥隔离。 |
|
|
141
|
+
| `awaiting_approvals` | 完整签名证据与冻结上下文;已收到的各方授权 | 原关系不变;只补缺失授权,不重写已验收内容。 |
|
|
142
|
+
| `ready` | 必要授权齐全,安全前置条件已确认 | 原关系不变;再次检查期限、当前 owner、版本和凭据代际后提交。 |
|
|
143
|
+
| `committed` | 新关系、提交回执、证据与审计记录、待发布/清理任务 | 新关系生效;各方只续跑自己的发布、删除和清理。 |
|
|
144
|
+
| `completed` | 必需文档投影和旧关系清理已完成,或被后续版本取代 | 返回原提交结果;可选托管仍按独立任务处理。 |
|
|
145
|
+
|
|
146
|
+
取消、失败、过期只发生在 committed 之前,该操作不改变权威关系;继续采用权威当前状态,不能因版本冲突恢复准备时的旧 owner。已完成的 rekey、凭据撤销不逆转。committed 后不能因文档、网络、托管失败回滚关系,也不因 operation 期限到达重新判为过期。
|
|
147
|
+
|
|
148
|
+
原提交回执永久对应原版本,查询时另行返回当前关系。后续版本已提交时,旧 operation 的发布/清理任务按目标版本标记为 `superseded`,不得重写或删除新关系的文档。
|
|
149
|
+
|
|
150
|
+
**唯一原子边界**是关系权威内部的小事务:CAS 更新关系,同时记录 operation 的 committed 状态、不可变提交回执、审计证据及后续任务。任一持久化失败均不返回提交成功。它不包含 Name Service、Storage、CA 或 SDK 网络调用;多实例必须共享一致存储,禁止各自维护关系副本。
|
|
151
|
+
|
|
152
|
+
## 5. 权限失效与可选托管
|
|
153
|
+
|
|
154
|
+
### 5.1 旧权限失效
|
|
155
|
+
|
|
156
|
+
关系授予的业务权限、Storage ACL 和下载票据必须绑定 `relation_id + relation_version`。服务端在实际使用 owner 权限时核对认证调用者为当前 owner、目标为对应 sub_aid,且关系为当前 active 版本;SDK 的先验检查或一份合法关系证据不能替代调用者授权。
|
|
157
|
+
|
|
158
|
+
transfer/release 提交后,旧版本权限立即不再有效,因此 ACL 元数据和旧 owner.md 可以异步清理。如果某服务不能在权限使用时检查版本,则相关 ACL、票据或长期凭据必须在提交前完成撤销/失效,并持久化阻断旧版本继续签发授权的屏障;未确认时停留在准备阶段,不能把安全撤权放进无约束的后台任务。屏障在提交或取消被权威确认前不得自行解除。
|
|
159
|
+
|
|
160
|
+
### 5.2 托管方式
|
|
161
|
+
|
|
162
|
+
托管默认关闭,显式启用后独立于关系操作推进。默认仅托管加密身份/恢复材料,custodian 保存或下载密文,解密密钥由应用管理;不因关系建立自动把 sub_aid 私钥、解密口令或已导入身份交给 owner。
|
|
163
|
+
|
|
164
|
+
封套固定 `version=3`、`algorithm=AES-256-GCM`、`kdf=PBKDF2-SHA256`、`iterations=200000`,包含 `sub_aid`、`relation_id`、`custody_generation`、`credential_generation`、`salt`、`nonce` 和包含16字节认证 tag 的 `ciphertext`。复用原实现的派生参数:16字节 salt、12字节 nonce;二进制字段使用严格 Base64,加密秘密由应用提供至少256 bit高熵随机值。每次新加密使用密码学安全的随机 salt/nonce,不复用 nonce;任务重试则重发已保存的原始封套。元数据使用以下 AAD 绑定,下载和恢复必须检查 AID、代际、证书与私钥是否匹配:
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
UTF-8("AUN-OWNERSHIP-CUSTODY-V3;") || JCS({sub_aid, relation_id, custody_generation, credential_generation})
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
解密秘密、明文私钥和身份包不进入公开文档或审计记录。该封套是 3.0 的独立格式,不能直接按旧 escrow 的固定 AAD 解密。恢复只在应用显式授权的 sub_aid 设备上导入;owner SDK 不自动装载 sub_aid 身份或代其执行操作。
|
|
171
|
+
|
|
172
|
+
### 5.3 已外发私钥的隔离
|
|
173
|
+
|
|
174
|
+
关系权威/托管服务记录身份材料代际及是否向旧 owner 外发过可解密材料;不能通过本次 `custody=false` 或删除本地配置消除记录。旧协议迁移且无法证明未外发时,按已外发处理。
|
|
175
|
+
|
|
176
|
+
如果旧 owner 曾取得可解密私钥,transfer/release 必须在提交前依次:停止向旧 owner 提供新的身份材料;sub_aid 在自己的设备持久化新密钥并完成 rekey;使旧证书、旧访问/刷新 token、设备会话及可恢复旧身份的凭据失效;由身份权威确认新的 credential generation。之后才生成目标签名文档和 operation approvals。
|
|
177
|
+
|
|
178
|
+
每一步都有持久化回执,可以独立重试;原关系在此期间保持不变,可选托管暂时不可用。无法确认凭据隔离时返回 `custody_rekey_required` 或 `credential_isolation_pending`,不得继续提交。新 owner 的托管授权在关系提交后另行启用。没有私钥外发时,不强制无意义的 rekey。
|
|
179
|
+
|
|
180
|
+
隔离回执绑定 operation、sub_aid、关系版本及凭据代际,必须由相应服务确认并可查询。关系权威核验服务端状态,不能接受客户端提供的“已撤销”布尔值作为凭据。
|
|
181
|
+
|
|
182
|
+
## 6. 共识检查、功能降级与审计
|
|
183
|
+
|
|
184
|
+
### 6.1 检查结果
|
|
185
|
+
|
|
186
|
+
`checkOwnershipConsensus(sub_aid)` 返回 `relation_state`、`document_state`、`authorized`、双方 AID、`relation_id`、`relation_version`、`operation_id` 及证据快照。
|
|
187
|
+
|
|
188
|
+
只有关系权威当前为 active、两份公开文件的签名有效,且关系标识、版本、operation 和双方 AID 与权威一致时,才返回 `authorized=true`。读取顺序为权威快照、两份文件、再次核对权威版本;变化则重试或返回 `relation_version_conflict`。真正执行受管理操作的服务仍须检查该版本,防止检查后转移或解绑。
|
|
189
|
+
|
|
190
|
+
| 文档情况 | `document_state` | 授权结果 |
|
|
191
|
+
| --- | --- | --- |
|
|
192
|
+
| 双方文件匹配当前 active 关系 | `consensus` | 可为 true |
|
|
193
|
+
| 已提交但尚未发布完整 | `pending` / `missing` | false,等待补发 |
|
|
194
|
+
| 只有旧版本或旧 owner 文件 | `stale` | false |
|
|
195
|
+
| 权威 unavailable,只有文件互相匹配 | `document_consensus` | false,只能展示历史声明 |
|
|
196
|
+
| 路径、字段或签名不合法 | `invalid` | false |
|
|
197
|
+
|
|
198
|
+
### 6.2 降级规则
|
|
199
|
+
|
|
200
|
+
能力发现分别报告协议版本、权威操作、双方文件服务、托管、rekey 与权限版本检查能力;未知能力不视为支持。
|
|
201
|
+
|
|
202
|
+
| 缺失能力/条件 | 允许的降级 | 不允许的行为 |
|
|
203
|
+
| --- | --- | --- |
|
|
204
|
+
| 未启用托管,或托管服务不可用 | 无托管的绑定、转移、解绑;保留待恢复托管任务 | 已外发私钥时跳过隔离 |
|
|
205
|
+
| 某一方离线或未授权 | 保存 operation,返回等待参与方 | 替对方签名或越过审批 |
|
|
206
|
+
| 提交后文件服务不可用 | 关系已提交、投影待发布;基本身份与消息继续使用 | 返回完整共识或回滚关系 |
|
|
207
|
+
| 关系权威不可用 | 本地保存 intent;只读验证历史文件 | 修改当前关系、使用缓存授予 owner 权限 |
|
|
208
|
+
| 参与方/服务只支持旧协议 | `legacy_read`,保留原关系,等待升级或显式迁移 | 自动退回 2.0 文件绑定、双协议并行写关系 |
|
|
209
|
+
| 凭据隔离或权限撤销能力不足 | 基本通信与只读检查,操作停留在准备阶段 | 宣称安全转移或解绑完成 |
|
|
210
|
+
|
|
211
|
+
没有 owner 或正在准备 operation 不影响 AID 的身份认证、普通通信和与 owner 无关的业务。需要 owner 共识的功能只在检查通过后开放。旧关系迁移必须携带既有当前 owner 授权、版本和凭据外发历史,不能按新 unbound 身份导入。
|
|
212
|
+
|
|
213
|
+
### 6.3 审计证据
|
|
214
|
+
|
|
215
|
+
关系提交审计保存固定 operation 上下文、各方 approval、提交前后状态/版本、双方完整签名文件快照、文档摘要、凭据隔离回执及提交回执。release 保留原 active 关系声明,transfer 同时保留旧关系与新关系声明。
|
|
216
|
+
|
|
217
|
+
需要 owner 关系的业务操作在执行前,持久化审计记录:业务操作标识、actor_aid、双方 AID、检查时间、权威版本/回执、双方声明原文与完整签名文件、实际服务端授权结果。只记哈希或可被删除的 URL 不足以证明历史声明。审计写入失败时不得继续受管理操作;关系后续撤销或文档删除不影响已保存证据。
|
|
218
|
+
|
|
219
|
+
## 7. 接口边界
|
|
220
|
+
|
|
221
|
+
| 能力 | 最小协议要求 | 0.5.18 参考入口 |
|
|
222
|
+
| --- | --- | --- |
|
|
223
|
+
| prepare | 固定操作参数、当前版本与期限,幂等生成 operation | `auth.aid_bind_prepare`、`auth.owner_change_prepare` |
|
|
224
|
+
| 提交本端证据/授权 | 验证调用者、文件签名和 operation approval,持久化进度 | `auth.aid_bind_submit`、`auth.owner_change_submit` |
|
|
225
|
+
| commit | 授权齐全、安全前置条件满足、CAS;重试返回原回执 | `auth.aid_bind_activate`、`auth.owner_change_activate`、`auth.owner_relation_unbind` |
|
|
226
|
+
| 查询/恢复 | 返回 operation 稳定阶段、缺失任务及当前关系 | `auth.aid_operation_get`、`auth.owner_relation_status` |
|
|
227
|
+
| 取消准备操作 | 仅发起者或该操作必须授权的参与方在提交前取消;保留证据 | 由上述 operation 控制面定义 |
|
|
228
|
+
| 文件发布 | sub_aid 自签自传 agent.md;owner_aid 自签自写 owner.md;带当前版本条件 | Name Service、Storage 现有数据面 |
|
|
229
|
+
| 托管/权限 | 独立密文对象、ACL、凭据代际及可查询回执 | Storage、Auth/CA 既有能力 |
|
|
230
|
+
|
|
231
|
+
以上是所需语义及复用方向,不表示原 RPC 原样具备 3.0 约束;特别是 unbind 必须纳入同一 operation、授权和审计边界。Message/Gateway 不新增 ownership 专用 P2P 消息,应用可通过已有消息或自己的流程通知参与方 operation_id;通知本身不是授权。
|
|
232
|
+
|
|
233
|
+
常见结果/错误:`waiting_participant`、`owner_approval_required`、`relation_version_conflict`、`idempotency_key_reuse`、`operation_expired`、`document_stale`、`authority_unavailable`、`custody_rekey_required`、`credential_isolation_pending`、`unsupported_capability`。返回值必须区分“意向已保存”“权威已提交”“文档已收敛”“可选托管已完成”。
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
本文是 legacy Agent.md 1.0 历史副本,不定义当前尾部文件签名或 Ownership 2.1。当前文件容器、可扩展 type、AID 和 ownership 字段以 [Ownership 协议定义 2.1](../Ownership协议定义2.1.md) 为准;[Ownership 2.0 Schema](../../agent.md/SCHEMA.md) 也属于历史版本。
|
|
6
6
|
|
|
7
|
-
当前 Group/Org
|
|
7
|
+
当前 Group/Org 使用实体主签、owner token 上传与可选 owner 附签,owner 必填且禁止通用 ownership/proof/release;Group 旧实体上传持续兼容,Org 不开放。通用多签精确字节及授权见 [当前协议 §2.4/§2.5](../Ownership协议定义2.1.md#24-文件签名),不采用本历史副本的签名方式。
|
|
8
8
|
|
|
9
9
|
## 限制
|
|
10
10
|
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# AUN SDK 0.5.21 应用集成指南
|
|
2
|
+
|
|
3
|
+
> 面向应用开发者。依据 `0.5.21` 工作区整理,相对基线为已发布的 `0.5.20`(`08221fbb`);当前 CHANGELOG 仍标记未发布,本文不表示发布包或部署环境已通过全部验收。
|
|
4
|
+
>
|
|
5
|
+
> 示例使用 TypeScript,默认运行于 Node.js;浏览器差异单独列出。SDK 实现者另读 [开发与移植指南](0.5.21-SDK开发与移植指南.md)。字段级定义见 [API 手册](06-API手册.md) 和各领域 RPC 手册。
|
|
6
|
+
|
|
7
|
+
## 1. 本版接入重点
|
|
8
|
+
|
|
9
|
+
| 能力 | 应用接入方式 | 相对 0.5.20 的重点 |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| 身份与连接 | `AIDStore` → `AID` → `AUNClient` | 保留原身份、设备、slot 和持久目录;服务端须明确支持 peer Pull |
|
|
12
|
+
| 消息同步 | `message.peers/pull/history` | 按完整 sender 隔离消费进度;目录估计不能当未读数 |
|
|
13
|
+
| 消息消费 | 三类 batch 或原逐条事件 | 处理器完成后才提交;失败可能重放,应用负责持久幂等 |
|
|
14
|
+
| 名片与元数据 | `store.resolve(aid, opts)` | 直接读取完整 `frontmatter`,按需附带 ownership 与 owner.md 快照 |
|
|
15
|
+
| Ownership | 原 2.1 工作流与共识检查 | 双文件和控制格式保持;增加本端未完成任务 reset,兼容历史任务 |
|
|
16
|
+
| 凭证与组织 | `credential`、`org` 门面及实体编排 | 取得当前托管凭证,自动续期、撤销同步及加密 checkpoint 恢复 |
|
|
17
|
+
| 诊断 | `client.debug.diag(scope)` | 分项 dry-run 报告,明确区分通过、失败和缺材料跳过 |
|
|
18
|
+
|
|
19
|
+
普通聊天应用先完成身份、消息持久化和连接;需要展示名片时调用 resolve。依赖 owner 授权、组织成员或 CAP 的业务,再接入对应的审批和完整验证流程。
|
|
20
|
+
|
|
21
|
+
## 2. 身份、运行环境与连接
|
|
22
|
+
|
|
23
|
+
### 2.1 选择产物与本地存储
|
|
24
|
+
|
|
25
|
+
Node.js 包为 `@agentunion/fastaun`,当前要求 Node.js `>=22.16.0`;浏览器包为 `@agentunion/fastaun-browser`。使用与目标版本一致的构建产物及锁文件,不能仅凭文档标题判断当前安装的版本。
|
|
26
|
+
|
|
27
|
+
`aunPath` 是应用级持久目录,可管理多个 AID。密钥、token、关系任务和续期 checkpoint 由 SDK 管理;应用自己的消息及业务事务另存数据库。启动时恢复原目录、密钥保护配置、设备与消费 slot。
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { AIDStore, AUNClient } from '@agentunion/fastaun';
|
|
31
|
+
const localAid = 'helper.agentid.pub';
|
|
32
|
+
const store = new AIDStore({
|
|
33
|
+
aunPath: process.env.AUN_PATH!,
|
|
34
|
+
encryptionSeed: process.env.AUN_SEED ?? '',
|
|
35
|
+
slotId: 'main', verifySsl: true,
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`AUN_PATH` 和 `AUN_SEED` 由应用部署提供。TLS 和自定义根证书在 `AIDStore` 配置,客户端从 AID 继承,详见 [连接与认证](04-连接与认证.md)。
|
|
40
|
+
|
|
41
|
+
### 2.2 首次注册与日常加载
|
|
42
|
+
|
|
43
|
+
仅在明确创建新身份时执行注册,然后加载同一身份;已有身份直接加载。普通 `agent` 可以不指定 owner,绑定关系可稍后单独申请。
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
const registered = await store.register(localAid, { type: 'agent' });
|
|
47
|
+
if (!registered.ok) throw new Error(registered.error.message);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
注册返回 `registered: true` 不代表 Ownership 已建立。指定 owner 只保存待审批意图,连接后继续原工作流;不要再重复发起绑定。`human` 禁止指定 owner;`group/org` 使用专属生命周期及实体身份编排。
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const loaded = store.load(localAid);
|
|
54
|
+
if (!loaded.ok) throw new Error(loaded.error.message);
|
|
55
|
+
const client = new AUNClient(loaded.data.aid);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`AUNClient` 接收 AID 对象,也可无参创建后 `loadIdentity()`;不要传 AID 字符串或旧版构造配置。先按第 3 节注册处理器,再调用 connect,避免启动补拉先于业务订阅。
|
|
59
|
+
|
|
60
|
+
### 2.3 浏览器差异
|
|
61
|
+
|
|
62
|
+
浏览器身份读取及存储使用异步接口和 IndexedDB。下面替换 Node.js 的初始化片段;后续消息门面的用法相同。
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { AIDStore as BrowserStore, AUNClient as BrowserClient } from '@agentunion/fastaun-browser';
|
|
66
|
+
const browserStore = new BrowserStore({ aunPath: 'myapp', encryptionSeed: '' });
|
|
67
|
+
const browserLoaded = await browserStore.load('helper.agentid.pub');
|
|
68
|
+
if (!browserLoaded.ok) throw new Error(browserLoaded.error.message);
|
|
69
|
+
const browserClient = new BrowserClient(browserLoaded.data.aid);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
浏览器 `aunPath` 是本地存储命名空间。Node 文件、文件 seed 轮换和浏览器密钥存储的使用方式有区别,不能直接复制磁盘目录操作。
|
|
73
|
+
|
|
74
|
+
### 2.4 连接与关闭边界
|
|
75
|
+
|
|
76
|
+
新 SDK 在 `auth.connect` 声明 `p2p_peer_pull_v1: true`,要求服务端以布尔 `true` 确认支持;缺失能力时返回 `unsupported_protocol`。升级应用前应核对 Gateway 和 Message 服务能力。
|
|
77
|
+
|
|
78
|
+
`connect()` 完成表示连接可用,后台消息补拉、Ownership 恢复和凭证续期可能仍在进行。界面分别展示连接状态、同步进度和业务任务状态;`auto_reconnect` 不代表业务已经完成。
|
|
79
|
+
|
|
80
|
+
## 3. 消息接收、发送与同步
|
|
81
|
+
|
|
82
|
+
### 3.1 选择 batch 或逐条消费
|
|
83
|
+
|
|
84
|
+
| 订阅事件 | `items` 中的原事件 |
|
|
85
|
+
| --- | --- |
|
|
86
|
+
| `message.batch` | `message.received`、`message.recalled` |
|
|
87
|
+
| `group.message_batch` | `group.message_created`、`group.message_recalled` |
|
|
88
|
+
| `group.event_batch` | `group.changed` |
|
|
89
|
+
|
|
90
|
+
三类批次均为 `{ namespace, items: [{ event, payload }], source }`。批次保持实际页内顺序,不跨页或 namespace;Push/inline 也可形成单元素批次,空批次不发布。
|
|
91
|
+
|
|
92
|
+
同类 batch 有订阅时,该页只发 batch;没有 batch 订阅时,沿用原逐条链路。不要依赖同时订阅两种形式收到两份事件。batch 模式及其处理器在每页开始时固定,订阅变化从下一页生效;逐条处理器仍动态查找。
|
|
93
|
+
|
|
94
|
+
下面的 `commitDeliveryBatch` 是应用实现的数据库事务函数,接收上述批次;只有消息、撤回状态及相关业务记录已经可靠提交,才完成 Promise。
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
declare function commitDeliveryBatch(batch: unknown): Promise<void>;
|
|
98
|
+
const subscriptions = [
|
|
99
|
+
client.on('message.batch', batch => commitDeliveryBatch(batch)),
|
|
100
|
+
client.on('group.message_batch', batch => commitDeliveryBatch(batch)),
|
|
101
|
+
client.on('group.event_batch', batch => commitDeliveryBatch(batch)),
|
|
102
|
+
];
|
|
103
|
+
await client.connect({ auto_reconnect: true });
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
业务处理要求:
|
|
107
|
+
|
|
108
|
+
1. 返回或 await 持久化 Promise;只启动后台写入就返回,会让 SDK 过早认定处理成功。
|
|
109
|
+
2. 写入失败向外抛出;吞掉错误等同于向 SDK 确认成功。失败不会自动改走逐条事件。
|
|
110
|
+
3. 按接收身份、会话、消息 ID 和事件语义持久幂等;消息创建与撤回分别处理,保留 tombstone,避免重放后恢复已撤回内容。
|
|
111
|
+
4. 多个处理器中已有部分成功,或业务提交后进程崩溃,仍可能重放整批。SDK 的 50,000 条运行时去重缓存不替代应用事务,也不保证跨 client、跨进程或跨重启只回调一次。
|
|
112
|
+
5. 在处理器外安排后续实时 Pull;不要在处理器内等待同一交付链再次发布事件,SDK 会拒绝这种等待重入。
|
|
113
|
+
|
|
114
|
+
Pull 内部页容量为 200,最多预取 4 页;应用共享排队容量默认按 `200 × 4` 计算。这些是 SDK 的流控边界,应用无需再写一套自动 Pull/ACK 循环。
|
|
115
|
+
|
|
116
|
+
### 3.2 发送与渲染提示
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const sent = await client.message.send({
|
|
120
|
+
to: 'alice.agentid.pub',
|
|
121
|
+
payload: { type: 'text', text: '你好' },
|
|
122
|
+
encrypt: true,
|
|
123
|
+
need_render: true,
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`message.send` / `group.send` 门面的参数沿用 RPC 字段 `need_render`;低层 TypeScript V2 编码选项使用 `needRender`,不能把两者混用。接收及返回保持 `need_render`,历史缺字段按可渲染处理。
|
|
128
|
+
|
|
129
|
+
`need_render=false` 只提示界面渲染策略,仍须正常消费、幂等保存和完成交付;它不是可信授权字段。需要受保护的业务元数据时,按 [ProtectedHeaders 专题](ProtectedHeaders用法专题.md) 接入。发送成功不代表对端应用已处理,也不等同于业务已读。
|
|
130
|
+
|
|
131
|
+
### 3.3 查询对端目录与主动补拉
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const pendingPeers = await client.message.peers({ filter: 'pending' });
|
|
135
|
+
const peerPage = await client.message.pull({
|
|
136
|
+
sender_aid: 'alice.agentid.pub', limit: 200,
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`message.peers` 是服务端消息消费目录,区别于本地身份目录 `client.peers()`:
|
|
141
|
+
|
|
142
|
+
- `filter: 'pending'` 一次返回完整待处理 peer,不能传 `limit/page_token`;`catalog_ready=false` 表示目录未准备好。
|
|
143
|
+
- `filter: 'all'` 查询仍有消息状态的 peer,可用 `limit`(1–200)与 `page_token` 翻页;它不是联系人列表。
|
|
144
|
+
- 每 peer 的进度由完整 `sender_aid` 隔离;seq 仍属于接收设备原收件箱,不是每个 sender 从 1 开始重新编号。
|
|
145
|
+
- 可选 `pending_count_estimate` 是整体持久 seq 跨度估计,可能明显偏大、不含 volatile;不能作为准确条数、未读数或完成比例。不要依赖已移除的逐 peer 精确计数字段。
|
|
146
|
+
|
|
147
|
+
省略 sender 的 `client.message.pull()` 会聚合全部 pending peer;使用返回的 `peers` 和 `partial` 判断各 peer 的结果。聚合请求不传 `after_seq`(包括 0)、`after_volatile_cursor`、`window_mode` 或 `force=true`,这些选项须指定 sender。
|
|
148
|
+
|
|
149
|
+
历史浏览使用 `message.history` / `group.history`,不推进实时水位、不 ACK,也不发布实时接收事件;翻页使用响应游标。`force`、Tail 和历史返回列表可能包含已交付消息,仍需按业务键合并。
|
|
150
|
+
|
|
151
|
+
自动同步、显式 Pull 和 Push 的应用交付使用同一处理链。不要将 Pull 返回列表再次作为另一份新消息写入非幂等业务,也不要用返回页的最大 seq 手工越过未交付消息 ACK。
|
|
152
|
+
|
|
153
|
+
### 3.4 UI 刷新、同步与业务已读
|
|
154
|
+
|
|
155
|
+
| 入口 | 应用用途 |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| batch 或原消息事件 | 消息与撤回的可靠业务入库 |
|
|
158
|
+
| `message.peers_snapshot` | 展示待处理对端、水位及可选整体积压估计;不承担入库提交 |
|
|
159
|
+
| `sync.started/progress/stopped` | 展示同步工作生命周期 |
|
|
160
|
+
| `delivery.changed` | 在已处理消息后合并刷新界面;其计数不是当前未读总数 |
|
|
161
|
+
| `message/group.read` | 用户实际阅读后上报业务已读位置 |
|
|
162
|
+
| `message/group.readState`、`read_changed`、`read_state_sync` | 查询、观察及重连补偿同一 AID 的跨设备已读汇总 |
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
await client.message.read({
|
|
166
|
+
scope: 'p2p', topic_key: 'inbox:primary',
|
|
167
|
+
last_read_message_id: 'm-100',
|
|
168
|
+
});
|
|
169
|
+
const readState = await client.message.readState({
|
|
170
|
+
scope: 'p2p', topic_key: 'inbox:primary',
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
业务已读与交付 ACK 分开。`read` 返回设备写入回执,共享状态以 `readState` 或有效变更事件为准。`current_device_seq=null` 保留原值;超出安全整数范围的 `last_read_order/current_device_seq` 在 TS/JS 中为精确十进制字符串,比较时可转 `BigInt`,不能先转 Number。完整接入见 [跨设备已读指南](../跨设备已读未读SDK集成指南.md)。
|
|
175
|
+
|
|
176
|
+
## 4. resolve:名片、frontmatter 与 owner 展示
|
|
177
|
+
|
|
178
|
+
### 4.1 普通名片读取
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const profile = await store.resolve('alice.agentid.pub');
|
|
182
|
+
if (!profile.ok) throw new Error(profile.error.message);
|
|
183
|
+
const frontmatter = profile.data.agent_md?.frontmatter;
|
|
184
|
+
console.log(frontmatter?.name, frontmatter?.description, frontmatter?.tags);
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
沿用 resolve,无需新增 frontmatter 查询方法。成功 `data` 包含 `aid`(AID 对象)、可选 `agent_md`、可选 `ownership` 和 `source`;`agent_md.content` 是完整原文,`agent_md.frontmatter` 是该名片的全部 YAML 元数据。
|
|
188
|
+
|
|
189
|
+
常用字段包括 `aid/name/type/version/exttype`、`description/avatar/tags`、`owner/ownership`、实体的 `entity_cert_fingerprint`;`visibility/skills` 及其它扩展键存在时也返回。嵌套对象、数组、字符串、数字、布尔值和 null 保留解析后的类型。扩展字段在 TypeScript 中为 `unknown`,使用前按应用数据约定缩小类型。
|
|
190
|
+
|
|
191
|
+
历史名片缺字段时不补默认值,裸 Markdown 的 frontmatter 为 `{}`。读取兼容不等于发布可省略当前 Schema 的必填字段。
|
|
192
|
+
|
|
193
|
+
### 4.2 按需获取 ownership
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const withOwner = await store.resolve('alice.agentid.pub', {
|
|
197
|
+
ownership: client, ownershipTtlMs: 60_000,
|
|
198
|
+
});
|
|
199
|
+
if (!withOwner.ok) throw new Error(withOwner.error.message);
|
|
200
|
+
console.log(withOwner.data.ownership?.status, withOwner.data.ownership?.owner_aid);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`ownership` 传已有 client 或实现共识接口的对象,不是布尔开关;SDK 复用 `checkOwnershipConsensus`,不另建连接。默认普通 resolve 不额外查询 Ownership。
|
|
204
|
+
|
|
205
|
+
| opts | 默认值 | 应用选择 |
|
|
206
|
+
| --- | --- | --- |
|
|
207
|
+
| `forceRefresh` | `false` | 刷新远端身份与名片;启用 ownership 时也绕过共识缓存 |
|
|
208
|
+
| `skipAgentMd` | `false` | 省略输出名片;显式请求 ownership 时,内部仍可读取权威名片 |
|
|
209
|
+
| `timeout` | 名片下载 10,000 ms | Node/浏览器沿用名片下载超时范围,共识调用使用所传 client 的配置 |
|
|
210
|
+
| `ownership` | 不传 | 普通展示不查询;需要关系状态时传当前 client |
|
|
211
|
+
| `ownershipTtlMs` | 60,000 ms | 展示缓存期限;`0` 每次重新查询 |
|
|
212
|
+
|
|
213
|
+
| `ownership.status` | 展示含义 |
|
|
214
|
+
| --- | --- |
|
|
215
|
+
| `consensus` | 当前双文件匹配且校验通过;此时 `owner_aid` 才非 null |
|
|
216
|
+
| `released` | 当前材料确认已释放,旧 owner 不再据此获权 |
|
|
217
|
+
| `unbound` | 当前有效权威名片没有关系声明,关系版本投影为 0 |
|
|
218
|
+
| `single_sided` | 单方声明或准备,稳定关系尚未成立 |
|
|
219
|
+
| `invalid` | 声明、签名或身份绑定等材料无效 |
|
|
220
|
+
| `unavailable` | 读取、网络、证书、服务能力或一致性不足,当前无法确认 |
|
|
221
|
+
| `not_applicable` | Group/Org 等使用专属生命周期 |
|
|
222
|
+
|
|
223
|
+
`checked_at` 为本次检查完成的 Unix 毫秒,`cached` 表示复用了快照。实际读取 owner 文件后,可选 `owner_md` 包含 `owner_aid/bucket/path/exists/content/sha256/observed_at`;正文含签名,`observed_at` 为 Unix 秒。确认不存在时 `exists=false` 且内容、摘要为空;没有读取时省略该对象。
|
|
224
|
+
|
|
225
|
+
SDK 将共识及 owner.md 原文一起缓存到 `agentmd.json.ownership_snapshot`,浏览器使用 IndexedDB 等价记录;不额外创建本地 owner.md 文件。目标、TTL、时钟及名片原文摘要须匹配才复用,`unavailable` 不复用。名片解析成功而额外共识失败时,外层仍成功,关系状态为 unavailable。
|
|
226
|
+
|
|
227
|
+
自有身份 resolve 可返回本地未发布草稿,共识检查仍读取远端原件,两者通过共识的 `agent_md_sha256` 区分。`frontmatter.owner`、legacy `verification.ownership_status` 和展示缓存均不授予 owner 权限;执行端须使用新鲜共识并核对当前调用者、sub、完整声明及权限范围。完整输入输出见 [resolve 规格](06-API手册.md#resolve-输入与输出)。
|
|
228
|
+
|
|
229
|
+
## 5. Ownership:审批、关系操作与恢复
|
|
230
|
+
|
|
231
|
+
### 5.1 使用现有 2.1 入口
|
|
232
|
+
|
|
233
|
+
| 发起角色或用途 | TypeScript 方法 |
|
|
234
|
+
| --- | --- |
|
|
235
|
+
| sub 申请 owner | `client.bindOwneraid(ownerAid)` |
|
|
236
|
+
| owner 申请管理 sub | `client.bindSubaid(subAid)` |
|
|
237
|
+
| 本端明确同意或拒绝请求 | `acceptOwnershipRequest(operationId)` / `rejectOwnershipRequest(operationId)` |
|
|
238
|
+
| 当前 owner 释放 sub | `client.releaseSubaid(subAid)` |
|
|
239
|
+
| 当前 owner 发起三方转移 | `client.transferSubaid(subAid, newOwnerAid)` |
|
|
240
|
+
| 查询当前权威关系 | `client.checkOwnershipConsensus(subAid)` |
|
|
241
|
+
|
|
242
|
+
应用在连接前订阅 `ownership.request/action_required/progress/completed/rejected/stopped/error`,保存 `operation_id` 与自己的业务记录。收到 request 后交由有权用户明确决定;应用审批不替代 SDK 的文件校验与最终共识。
|
|
243
|
+
|
|
244
|
+
当前关系继续由 NS `agent.md` 和 owner Storage `default/sub_aids/{subAid}/owner.md` 确认。声明六字段和 `aun.ownership.sdk.v1` 控制格式沿用;无需迁移到独立关系资源。
|
|
245
|
+
|
|
246
|
+
任务 completed 表示该次操作曾完成;之后的释放或转移不会抹去历史。展示当前关系另查共识。普通名片读取、正文更新不要求 owner Storage 在线或先有共识;更新仍须保留已有关系材料,并由 SDK 按本人签名和原 ETag/CAS 提交。
|
|
247
|
+
|
|
248
|
+
Group/Org 使用专属创建、转让、rekey 和实体名片流程,通用共识为 not_applicable。详细审批及关系操作见 [Ownership 应用指南](Ownership2.1-SDK应用集成指南.md)。
|
|
249
|
+
|
|
250
|
+
### 5.2 reset 的使用边界
|
|
251
|
+
|
|
252
|
+
仅在用户明确要归档本端发起的未完成任务时执行:
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
const reset = await client.resetOwnershipTask();
|
|
256
|
+
console.log(reset.reset_operation_ids);
|
|
257
|
+
console.log(reset.skipped_operation_ids);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
该方法无参数,只处理当前 AID 发起的未完成绑定、释放、转移,保留终态历史、参与他人发起的任务及远端文件。无法安全判断的记录列入 skipped。reset 不解绑、不解锁、不删除 owner.md,也不自动发起新关系;不要放在每次启动或网络失败的通用重试逻辑中。
|
|
261
|
+
|
|
262
|
+
升级后先恢复原存储和原任务。0.5.20/0.5.19 的 operation、有效审批、原签名字节及原提交条件继续保留;网络、IO 或 CAS 冲突不应通过 reset 清空现场。历史边界见 [编排指南恢复章节](Ownership-SDK编排指南2.1.md#8-崩溃与响应丢失后的恢复)。
|
|
263
|
+
|
|
264
|
+
## 6. 凭证与组织集成
|
|
265
|
+
|
|
266
|
+
### 6.1 取得当前托管凭证
|
|
267
|
+
|
|
268
|
+
`credential.current` 是本地查询,输入为完整凭证或 CID,沿续期链返回当前托管记录,未找到为 null;记录的 `credential` 才是 CAP,可能还带 `membership_binding` 等材料。它不是新增的服务端 RPC,也不表示刚查询过远端授权状态。
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
declare const originalCredentialCid: string;
|
|
272
|
+
const managed = await client.credential.current(originalCredentialCid);
|
|
273
|
+
if (!managed) throw new Error('没有当前托管凭证');
|
|
274
|
+
const currentCredential = managed.credential;
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
业务请求应使用当前凭证及配套 binding,不长期复用初始化时截取的旧 CAP。完整 `credential.verify` 仍须验证证书、时间、audience、父链、当前状态、能力范围及实际请求绑定;`verifySignature` 只做签名预检。
|
|
278
|
+
|
|
279
|
+
对于 SDK 已托管且具备续期材料的长期凭证,进入 READY 后恢复并检查续期,在线期间每 60 秒重新扫描。续期使用加密请求/响应、登记回执及提交确认,断线后复用原 checkpoint。缺少颁发方、登记或成员材料时,不能仅靠启用连接获得有效新凭证。
|
|
280
|
+
|
|
281
|
+
已知撤销状态会用于当前凭证与证明链检查;旧 CAP 不因曾经有效而获得豁免。服务不可用、状态未知或回执不匹配时,暂停依赖该凭证的副作用操作。
|
|
282
|
+
|
|
283
|
+
### 6.2 组织业务请求
|
|
284
|
+
|
|
285
|
+
Credential 和 Org 业务 RPC 通过 Gateway service-plane;facade 存在不等于服务已经部署。组织受保护读取同样需要有效授权和请求绑定。
|
|
286
|
+
|
|
287
|
+
下面的 `orgParams` 由应用提供,包含目标 `org_id`、当前成员 CAP/binding 及该方法所需业务字段;signer 来自当前认证主体,服务 AID 来自部署发现。
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
import type { CredentialSigner, JsonObject } from '@agentunion/fastaun';
|
|
291
|
+
declare const orgParams: JsonObject;
|
|
292
|
+
declare const memberSigner: CredentialSigner;
|
|
293
|
+
declare const orgServiceAid: string;
|
|
294
|
+
const prepared = client.org.prepareRequest(
|
|
295
|
+
'org.member.list', orgParams, orgServiceAid, memberSigner,
|
|
296
|
+
);
|
|
297
|
+
const members = await client.org.member.list(prepared);
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
先准备完整授权包,再由 helper 生成 AAD、request binding 等材料;已签请求按原参数重试,不能签后修改业务字段。首次 join/inviteAccept 使用 admission 流程,目标成员仍须本人签名;owner 的代表证明不能替代成员签名。
|
|
301
|
+
|
|
302
|
+
| 场景 | 接入要求 |
|
|
303
|
+
| --- | --- |
|
|
304
|
+
| 创建组织 | 使用 `client.createOrg(params, { aidStore: store })` 等高层入口,持久保存组织实体密钥和创建 checkpoint |
|
|
305
|
+
| 入组/邀请 | 使用双方签署的 membership binding、成员 CAP 和登记授权;回执验证完成后才最终化 |
|
|
306
|
+
| 成员续期 | 保留原成员关系及版本,新 CAP 登记确认后再撤旧 CAP;使用 `renewCredential` 或原自动续期流程 |
|
|
307
|
+
| 转让组织 | 专属两阶段转让、rekey 和新证书;恢复同一 proposal、身份及原请求,不复制旧私钥给新 owner |
|
|
308
|
+
| 组织名片 | 实体私钥主签,当前 owner 以本人 token 上传;可选 owner 附签,保留完整原文及原 CAS |
|
|
309
|
+
|
|
310
|
+
`org.resource.create`、`org.task.create`、`org.host.add`、`org.workflow.create` 当前为 `NOT_IMPLEMENTED` 占位,不据此构建已可用功能。完整流程见 [凭证与组织应用指南](凭证与组织服务SDK应用集成指南.md);本版续期、撤销及恢复变化以本文和 `python/CHANGES_FOR_PARITY.md` 的 0.5.21 章节补充。
|
|
311
|
+
|
|
312
|
+
## 7. 诊断与错误处理
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
const report = await client.debug.diag('message.*');
|
|
316
|
+
console.log(report.passed, report.failed, report.skipped);
|
|
317
|
+
for (const check of report.checks) {
|
|
318
|
+
console.log(check.method, check.status, check.stage, check.reason);
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
scope 为空或 `*` 检查全部,`message` / `message.*` 选命名空间,完整 RPC 名精确选择,`debug` 显示用法。报告含当前 AID、分项阶段、耗时和汇总;缺少真实业务材料会 skipped。
|
|
323
|
+
|
|
324
|
+
SDK 要求服务端确认 `dry_run=true`、`executed=false`。诊断通过说明对应 dry-run 阶段通过,不代表发送、审批、Storage 写入或完整跨域业务已执行成功;skipped 也不是通过。
|
|
325
|
+
|
|
326
|
+
| 失败入口 | 应用处理 |
|
|
327
|
+
| --- | --- |
|
|
328
|
+
| Store 的 `Result.ok=false` | 读取 `error.code/message`,保留原始失败,不继续使用缺失的身份或名片 |
|
|
329
|
+
| RPC/工作流抛异常 | 按 `AUNError` 数字 `code`、字符串 `stringCode` 及 `retryable` 分类;不解析错误文本 |
|
|
330
|
+
| 共识 unavailable | 展示当前不可确认,待恢复后查询;不将其改成 unbound 或授权成功 |
|
|
331
|
+
| CAS/目标/幂等键冲突 | 核对原任务及权威事实,停止盲重试;不刷新条件覆盖后续状态 |
|
|
332
|
+
| CAP/成员状态未知或已撤销 | 停止依赖授权的操作,恢复受信状态与验证链 |
|
|
333
|
+
| 消息持久化失败 | 让处理器失败并保留重放责任,以相同业务键恢复 |
|
|
334
|
+
|
|
335
|
+
## 8. 升级、重启与验收
|
|
336
|
+
|
|
337
|
+
从 0.5.20 升级时按以下顺序接入:
|
|
338
|
+
|
|
339
|
+
1. 核对服务端 peer 能力及目标 SDK 产物;保留原 `aunPath`、设备、slot 和解密配置。
|
|
340
|
+
2. 选择 batch 或原逐条消费,确保入库 Promise 与幂等键正确;移除应用自己提前 ACK 的逻辑。
|
|
341
|
+
3. 将 P2P 主动历史与指定游标调用绑定到 sender;聚合 Pull 按 `peers/partial` 处理,目录估计仅用于展示。
|
|
342
|
+
4. 名片页面改用 `agent_md.frontmatter`,需要 owner 展示时才启用 ownership;执行权限继续新鲜校验。
|
|
343
|
+
5. 恢复原 Ownership、组织和续期 checkpoint,不通过清库、重注册或启动 reset 来“修复”失败。
|
|
344
|
+
6. 请求前取得当前托管 CAP 及匹配 binding,保留真实登记回执和原已签请求。
|
|
345
|
+
|
|
346
|
+
上线验收至少覆盖:消息批次入库失败和整批重放、断线后补拉、撤回重复、volatile-only peer、不同 sender 并行、身份切换旧响应隔离;名片缺字段和扩展类型、owner 缓存刷新及 unavailable;审批后崩溃、历史任务恢复与 reset 保留远端文件;凭证续期、撤销坏页、组织转让恢复,以及诊断 skipped。
|
|
347
|
+
|
|
348
|
+
正常退出时停止业务入口,再释放订阅和客户端:
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
for (const subscription of subscriptions) subscription.unsubscribe();
|
|
352
|
+
await client.close();
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
本指南的短示例用于说明公开调用方式;完整业务函数及授权材料由应用实现。单域、跨 SDK、浏览器联网和双域验收分别记录,不能用类型检查或 dry-run 替代。
|
|
356
|
+
|
|
357
|
+
## 9. 按领域继续查阅
|
|
358
|
+
|
|
359
|
+
| 需求 | 文档 |
|
|
360
|
+
| --- | --- |
|
|
361
|
+
| 全部公开输入输出与事件 | [API 手册](06-API手册.md) |
|
|
362
|
+
| peer、Pull/History/ACK、TTL 和目录 | [Message RPC](09-message-rpc-manual.md) |
|
|
363
|
+
| 群生命周期、消息、成员与 Group FS | [Group RPC](09-group-rpc-manual.md) |
|
|
364
|
+
| Ownership 审批、签验与恢复 | [Ownership 应用指南](Ownership2.1-SDK应用集成指南.md) |
|
|
365
|
+
| CAP、成员及组织业务闭环 | [凭证与组织应用指南](凭证与组织服务SDK应用集成指南.md) |
|
|
366
|
+
| 文件、ACL、上传下载 | [Storage RPC](09-storage-rpc-manual.md) |
|
|
367
|
+
| 文档协作与流 | [Collab RPC](09-collab-rpc-manual.md)、[Stream RPC](09-stream-rpc-manual.md) |
|
|
368
|
+
| 实现其它语言 SDK 或检查语义差异 | [0.5.21 开发与移植指南](0.5.21-SDK开发与移植指南.md) |
|