@agentunion/fastaun 0.5.20 → 0.5.22

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 (128) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/_packed_docs/CHANGELOG.md +104 -0
  3. package/_packed_docs/INDEX.md +59 -34
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +59 -52
  5. 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
  6. 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
  7. 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
  8. 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
  9. package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +307 -67
  10. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +41 -15
  11. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1433 -1392
  12. package/_packed_docs/protocol/08-AUN-E2EE.md +17 -12
  13. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +30 -8
  14. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +2 -0
  15. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +33 -22
  16. 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
  17. 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
  18. package/_packed_docs/sdk/0.5.22-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +212 -0
  19. package/_packed_docs/sdk/0.5.22-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +199 -0
  20. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +1 -1
  21. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +5 -1
  22. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +64 -64
  23. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +4 -1
  24. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +42 -39
  25. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +163 -14
  26. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +48 -47
  27. package/_packed_docs/sdk/09-group-rpc-manual.md +15 -2
  28. package/_packed_docs/sdk/09-message-rpc-manual.md +250 -160
  29. package/_packed_docs/sdk/09-storage-rpc-manual.md +64 -7
  30. package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +73 -0
  31. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +90 -0
  32. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +33 -25
  33. package/_packed_docs/sdk/INDEX.md +67 -33
  34. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +74 -57
  35. 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 +312 -300
  36. 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 +322 -382
  37. 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 -708
  38. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +28 -20
  39. 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 +190 -97
  40. 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 +158 -127
  41. package/dist/agent-md-schema.js +6 -4
  42. package/dist/agent-md-schema.js.map +1 -1
  43. package/dist/agent-md.d.ts +22 -2
  44. package/dist/agent-md.js +92 -68
  45. package/dist/agent-md.js.map +1 -1
  46. package/dist/aid-store.d.ts +13 -0
  47. package/dist/aid-store.js +50 -15
  48. package/dist/aid-store.js.map +1 -1
  49. package/dist/auth.d.ts +1 -0
  50. package/dist/auth.js +22 -2
  51. package/dist/auth.js.map +1 -1
  52. package/dist/cert-utils.d.ts +1 -0
  53. package/dist/cert-utils.js +13 -0
  54. package/dist/cert-utils.js.map +1 -1
  55. package/dist/client/delivery.d.ts +87 -1
  56. package/dist/client/delivery.js +1387 -139
  57. package/dist/client/delivery.js.map +1 -1
  58. package/dist/client/group-state.js +3 -0
  59. package/dist/client/group-state.js.map +1 -1
  60. package/dist/client/rpc-pipeline.d.ts +4 -1
  61. package/dist/client/rpc-pipeline.js +149 -37
  62. package/dist/client/rpc-pipeline.js.map +1 -1
  63. package/dist/client/v2-e2ee.d.ts +12 -2
  64. package/dist/client/v2-e2ee.js +831 -304
  65. package/dist/client/v2-e2ee.js.map +1 -1
  66. package/dist/client.d.ts +26 -2
  67. package/dist/client.js +412 -68
  68. package/dist/client.js.map +1 -1
  69. package/dist/config.d.ts +4 -0
  70. package/dist/config.js +1 -0
  71. package/dist/config.js.map +1 -1
  72. package/dist/events.d.ts +18 -1
  73. package/dist/events.js +148 -9
  74. package/dist/events.js.map +1 -1
  75. package/dist/facades.d.ts +43 -1
  76. package/dist/facades.js +363 -7
  77. package/dist/facades.js.map +1 -1
  78. package/dist/group-fs.d.ts +1 -0
  79. package/dist/group-fs.js +37 -19
  80. package/dist/group-fs.js.map +1 -1
  81. package/dist/index.d.ts +5 -3
  82. package/dist/index.js +1 -1
  83. package/dist/index.js.map +1 -1
  84. package/dist/keystore/aid-db.d.ts +6 -1
  85. package/dist/keystore/aid-db.js +184 -42
  86. package/dist/keystore/aid-db.js.map +1 -1
  87. package/dist/keystore/index.d.ts +14 -0
  88. package/dist/keystore/local-token-store.d.ts +9 -1
  89. package/dist/keystore/local-token-store.js +79 -14
  90. package/dist/keystore/local-token-store.js.map +1 -1
  91. package/dist/org-protocol.d.ts +46 -0
  92. package/dist/org-protocol.js +802 -12
  93. package/dist/org-protocol.js.map +1 -1
  94. package/dist/ownership-v21.d.ts +36 -5
  95. package/dist/ownership-v21.js +168 -52
  96. package/dist/ownership-v21.js.map +1 -1
  97. package/dist/ownership-workflow.d.ts +24 -2
  98. package/dist/ownership-workflow.js +682 -41
  99. package/dist/ownership-workflow.js.map +1 -1
  100. package/dist/secret-store/file-store.js +84 -0
  101. package/dist/secret-store/file-store.js.map +1 -1
  102. package/dist/seq-tracker.d.ts +1 -0
  103. package/dist/seq-tracker.js +2 -2
  104. package/dist/seq-tracker.js.map +1 -1
  105. package/dist/storage/lowlevel.d.ts +6 -0
  106. package/dist/storage/lowlevel.js +24 -7
  107. package/dist/storage/lowlevel.js.map +1 -1
  108. package/dist/storage/read-cache.d.ts +70 -0
  109. package/dist/storage/read-cache.js +625 -0
  110. package/dist/storage/read-cache.js.map +1 -0
  111. package/dist/storage/vfs.d.ts +2 -0
  112. package/dist/storage/vfs.js +50 -15
  113. package/dist/storage/vfs.js.map +1 -1
  114. package/dist/tools/cross-sdk-agent.d.ts +86 -3
  115. package/dist/tools/cross-sdk-agent.js +758 -46
  116. package/dist/tools/cross-sdk-agent.js.map +1 -1
  117. package/dist/transport.d.ts +3 -0
  118. package/dist/transport.js +104 -46
  119. package/dist/transport.js.map +1 -1
  120. package/dist/types.d.ts +1 -0
  121. package/dist/v2/e2ee/encrypt-group.js +1 -0
  122. package/dist/v2/e2ee/encrypt-group.js.map +1 -1
  123. package/dist/v2/e2ee/encrypt-p2p.js +1 -0
  124. package/dist/v2/e2ee/encrypt-p2p.js.map +1 -1
  125. package/dist/v2/e2ee/types.d.ts +1 -0
  126. package/dist/version.d.ts +1 -1
  127. package/dist/version.js +1 -1
  128. package/package.json +1 -1
@@ -1,300 +1,312 @@
1
- # Ownership 2.1 SDK 应用集成指南
2
-
3
- 本文面向应用开发者,以当前工作区的 Node.js TypeScript SDK 为例,说明身份准备、发起关系操作、接入审批界面或自动策略、跟踪结果与断线恢复。协议依据为 [Ownership 协议定义 2.1](../protocol/Ownership协议定义2.1.md);编排契约见 [Ownership SDK 编排指南 2.1](Ownership-SDK编排指南2.1.md),实现边界见 [Ownership 2.1 详细设计](Ownership2.1详细设计.md)。
4
-
5
- 需要实现或移植 SDK 内部机制时,查阅 [Ownership 2.1 SDK 开发与移植指南](Ownership2.1-SDK开发与移植指南.md);本文聚焦应用公有接口。
6
-
7
- 本文使用当前 [包入口](../../ts/src/index.ts) 和 [AUNClient](../../ts/src/client.ts) 的公有 API。工作区包名为 `@agentunion/fastaun`、参考版本为 `0.5.19`,要求 Node.js `>=22.16.0`,见 [package.json](../../ts/package.json)。这些信息描述当前源码,不表示同版本 npm 包已经发布或包含本工作区的全部 2.1 实现。旧 `Ownership-SDK集成指南.md`、`Ownership-SDK实现指南.md` 属于 legacy;协议 3.0 不属于本文范围。
8
-
9
- 兼容方向为新服务端兼容新旧 SDK 的既有身份认证、普通名片和通信入口,并保留旧 SDK 的 legacy owner 操作;新 SDK 的 2.1 关系操作不兼容旧服务端。Ownership 2.1 当前关系始终重新核对两份当前文件;旧 SDK 的旧格式关系由隔离的 Auth JSONL、operation ID 和 NS ownership_proof 兼容,不生成 2.1 双文件或共识,也不得覆盖已存现代声明。不把新 SDK 源码调用形态兼容作为本契约要求。
10
-
11
- ## 1. 应用需要理解的关系边界
12
-
13
- `group/org` 作为被管理的 `sub` 时使用自身生命周期:创建自动建立 owner,解散自动解除,专属转移强制 rekey,身份材料始终由当前 owner 持有;它们不适用本指南针对 `sub` 的绑定、释放、转移和审批流程。Group/Org 仍可按普通主体关系中的 owner 规则作为 `owner_aid`。将 Group/Org 作为 `sub` 调用任务 Facade 会 reject/抛出 `not_applicable`(`retryable=false`);对其调用 `checkOwnershipConsensus` 才会返回 `status/code=not_applicable` 的共识结果对象。名片必须含 owner,必须省略 ownership、ownership_proof、ownership_release,并由实体私钥主签、当前 owner 使用本人 token 上传,可选追加 owner 附签;完整格式见 [协议 §2.5](../protocol/Ownership协议定义2.1.md#25-grouporg-名片的实体主签与-owner-上传)。Group 入口见 [Group RPC Manual](09-group-rpc-manual.md#群组生命周期),Org 沿用专属 0.8 生命周期,不把组织成员双签解释为 Ownership 2.1。
14
-
15
- 现代 Group/Org 文件的 `entity_cert_fingerprint` 与主签 `cert_fingerprint` 必须是相同的完整 `sha256:<64位小写hex>`,主块显式 `signer_aid=实体AID`;每个附签必须是当前 owner,存在就必须全验。只有 type=group、恰好一个签名块、未出现 entity_cert_fingerprint 且主块 signer_aid 缺省或等于群 AID 的文件才可走旧 Group 读取兼容;字段已出现但无效不能按旧格式放行,Org 没有此入口。
16
-
17
- Ownership 是 `agent.md` 上叠加的可选关系属性。Ownership 关系无效或暂时不可确认,只限制依赖该关系的授权、绑定、释放、转移等操作;它本身不会使基础格式和外层签名有效的 `agent.md` 失效。普通读取、下载、基础验签及通信仍可继续。NS 兼容旧 SDK 不带 Ownership 专用 Header 的普通读写和旧格式名片上传;旧关系字段在正文更新时必须原样保留。新 SDK 新建关系或提交新格式时仍须执行当前 Ownership 规则,不能用旧客户端兼容入口绕过校验。
18
-
19
- | 名称 | 应用中的含义 |
20
- | --- | --- |
21
- | `sub_aid` | 被管理身份;签署自己的 `agent.md`,以自己的认证身份提交到 NS。 |
22
- | `owner_aid` | 绑定目标或当前/原 owner;签署、发布自己 Storage 中的 `owner.md`。 |
23
- | `new_owner_aid` | 转移目标;独立签署、发布自己的目标 `owner.md`。 |
24
- | NS | 以数据库事务和 CAS 持久化 sub 的权威 `agent.md` 与同步待办,根据该名片和 owner 的权威 `owner.md` 验证当前关系。 |
25
- | Storage | 保存 owner 的权威 `owner.md`,以及 NS 异步同步的 sub 名片副本。 |
26
-
27
- 每个参与身份都需要自己的密钥、证书和客户端。owner 权限不等于持有 sub 私钥,也不授予代签或代上传能力。owner 文件位于 `owner_aid:/sub_aids/{sub_aid}/owner.md`;sub 的权威名片位于 NS,`sub_aid:/agent.md` 是其 Storage 副本。
28
-
29
- Ownership 2.1 关系事实只来自 sub 的权威 `agent.md` 与 owner 签署、保存在自己 Storage 中的权威 `owner.md`。`owner_aid` 是 `owner.md` 中的 owner 身份字段,不是独立文件或数据库关系记录。NS 的数据库事务只保证 `agent.md` 原文、CAS 更新与同步待办的原子性,不另存关系账本或验收证据表,不依赖 `ownership.journal`、独立关系日志或 reserve-confirm 恢复流程。SDK 本地任务数据库仅用于恢复本端编排任务,不是关系事实的替代来源。
30
-
31
- 应用调用 Facade 表达意愿,SDK 通过普通加密 P2P 消息协调各端自己的文件操作,NS 验收结果决定关系。本指南的 2.1 编排不新增 ownership 专用 RPC,也不需要应用自行构造控制消息或调用内部文件方法。文件角色、上传身份及 owner 锁约束见 [协议第 1、2 节](../protocol/Ownership协议定义2.1.md#1-权威文档与-owner-锁)。
32
-
33
- ## 2. 接入前提与能力检查
34
-
35
- | 前提 | 接入要求与不足时的处理 |
36
- | --- | --- |
37
- | 独立身份 | 各参与端加载本身份可用的私钥和证书。`AIDStore.load()` 成功也可能只得到公钥证书,仍须检查 `isPrivateKeyValid()`。 |
38
- | 初始名片 | NS 上已有 sub 自己签署、上传的初始 `agent.md`。可用 `AIDStore.downloadAgentMd(subAid)` 确认可读;真正的关系变更仍由 Facade 新鲜检查。不存在时会遇到 `unavailable`,不能以本地空白名片代替。 |
39
- | NS 2.1 | 部署支持基于两份权威文件的 2.1 新鲜关系检查,以及名片和同步待办的原子 CAS。只读共识检查遇到不支持时返回 `unavailable`,其 `code` 可为 `unsupported_protocol`。 |
40
- | Storage | 部署支持权威对象查询和完整文件原子发布;写入前核对起始完整原文、摘要和存在性,清理前核对当前 NS 和本任务完整原件。 |
41
- | P2P 编排 | 参与端运行支持当前编排的 SDK。对端离线或不能处理请求时保持等待,不把超时、ACK 或投递成功当作批准。 |
42
- | 持久任务存储 | 固定、可写、可恢复的数据目录;创建和更新任务必须能够原子保存。存储不可用或损坏时停止有副作用的编排。 |
43
- | 可信根与当前证书状态 | 安全配置根证书,验证证书链、用途和当前撤销状态。TLS 校验与文件签名验证都需要成立。 |
44
-
45
- `checkOwnershipConsensus()` 是当前关系的只读预检,不是全部服务能力的探测接口。尤其是无 owner 时,它不会验证尚未读取的 owner Storage 发布能力;部署能力仍需由服务配置和验收结果确认。
46
-
47
- `AIDStore` 的配置参数是 `aunPath`、`encryptionSeed`、`slotId?`、`verifySsl?`、`rootCaPath?`、`debug?`,见 [AIDStore](../../ts/src/aid-store.ts)。生产应用应显式设置 `verifySsl: true`,通过可信部署渠道配置 `rootCaPath`;该路径用于 SDK 的 AUN 证书信任验证,不自动替代 Node.js HTTPS/TLS 自身的信任配置。私有 TLS 站点仍需正确配置 Node.js 的 TLS 信任,不能仅凭该路径就视为可信。不能用对端提供的任意根替换本地信任配置。服务发现及外部地址使用部署域名,例如 `ns.agentid.pub`、`st.agentid.pub`。
48
-
49
- 默认数据根为用户目录的 `.aun`。当前本地存储在首选目录不可用时还可能回退到工作目录的 `.aun`;应用应事先确保配置的固定绝对目录可写,避免重启或工作目录变化后使用另一份数据。任务保存于 `{aunPath}/AIDs/{aid}/aun.db`,与该身份的密钥、证书、本地 secret store 和稳定设备信息一起保留。`slotId` 也应固定;它不是任务数据库的隔离目录。实际路径逻辑见 [LocalTokenStore](../../ts/src/keystore/local-token-store.ts) 和 [配置实现](../../ts/src/config.ts)。
50
-
51
- `persistence_unavailable` 表示本地任务存储能力缺失、数据库恢复不可用、任务记录损坏或原子保存失败;远端 NS ETag、owner 原件或原 NS CAS 条件变化属于 `conflict`,不是本地持久化故障。它不是连接成功后就能忽略的提示;Facade 可抛出该错误,恢复也会停止。只读共识检查不依赖本地任务存储,不能用其成功证明任务可持久化。
52
-
53
- ## 3. 最小 TypeScript 接入
54
-
55
- ### 3.1 装载存量身份
56
-
57
- 以下 `appConfig` 由应用自行读取,类型为 `{ aunPath: string; encryptionSeed: string; rootCaPath: string }`。`aunPath` 为固定持久绝对目录,`encryptionSeed` 从应用自己的秘密配置提供;这些不是 `AUNClient` 构造参数。
58
-
59
- ```ts
60
- import { AIDStore, AUNClient } from '@agentunion/fastaun';
61
- const store = new AIDStore({
62
- aunPath: appConfig.aunPath, encryptionSeed: appConfig.encryptionSeed,
63
- rootCaPath: appConfig.rootCaPath, verifySsl: true, slotId: 'ownership-app',
64
- });
65
- const loaded = store.load('helper.agentid.pub');
66
- if (!loaded.ok) throw new Error(loaded.error.message);
67
- if (!loaded.data.aid.isPrivateKeyValid()) throw new Error('本身份私钥不可用');
68
- const client = new AUNClient(loaded.data.aid);
69
- ```
70
-
71
- 构造函数接收 `AID` 对象或无参,不接收 AID 字符串、配置对象或其它身份的凭据。需要延后装载时,可在无身份或已关闭状态调用 `loadIdentity(aid)`;无参构造会先使用默认数据配置,本例直接传入已装载的 AID,使客户端沿用其 `aunPath`、设备、slot、TLS 和可信根配置。连接选项传给 `connect()`,不是构造函数。
72
-
73
- ### 3.2 首次注册的独立分支
74
-
75
- 没有本地身份时,先通过同一个 `AIDStore` 注册,再执行上述装载流程。下面是首次注册分支,不是每次启动都执行的步骤:
76
-
77
- ```ts
78
- const registered = await store.register('helper.agentid.pub', {
79
- type: 'agent', owner: 'owner.agentid.pub',
80
- });
81
- if (!registered.ok) throw new Error(registered.error.message);
82
- ```
83
-
84
- `register()` 返回 `Result<{ registered: true }>`,并尝试以本身份条件创建初始名片。`type: 'agent'` 的 `owner` 可省略;省略时只初始化普通 `agent.md`,不保存 Ownership 关系意图。有 owner 时保存固定 `operation_id` 的 owner 注册意图;初始名片不直接写入 owner 关系,首次连接后 SDK 用原意图继续绑定,owner 仍须审批。应用需确认初始名片已可用,不能把 `registered: true` 当作关系建立完成,也不能再调用绑定发起接口来“继续注册”。`type: 'human'` 禁止提供 owner,`group/org` 要求当前 owner 并沿用专属生命周期。注册与恢复见 [AIDStore.register](../../ts/src/aid-store.ts) 和 [设计第 7.1 节](Ownership2.1详细设计.md#71-七个-facade-与内部复用)。
85
-
86
- ### 3.3 先订阅,再连接
87
-
88
- 事件处理器类型是 `(payload) => void | Promise<void>`,直接收到载荷,没有 `event.data` 包装。以下 `showApproval`、`updateOwnershipView` 为应用自实现函数;签名分别为 `showApproval(payload: Parameters<EventHandler>[0]): void`、`updateOwnershipView(event: string, payload: Parameters<EventHandler>[0]): void | Promise<void>`。应用负责按第 5 节字段解析、保存和展示载荷。
89
-
90
- ```ts
91
- import type { EventHandler } from '@agentunion/fastaun';
92
- const onRequest: EventHandler = payload => showApproval(payload);
93
- client.on('ownership.request', onRequest);
94
- const events = ['ownership.action_required', 'ownership.progress', 'ownership.completed',
95
- 'ownership.rejected', 'ownership.stopped', 'ownership.error'];
96
- for (const event of events) client.on(event, payload => updateOwnershipView(event, payload));
97
- await client.connect({ auto_reconnect: true });
98
- ```
99
-
100
- `connect()` 使用已装载身份完成认证。连接及重连成功后会在后台触发注册意图和 Ownership 任务恢复,`await connect()` 返回不代表所有恢复任务完成。连接前订阅可接到恢复中的审批或终局事件;页面卸载时可对 `on()` 返回的 `Subscription` 调用 `unsubscribe()`。接线见 [AUNClient](../../ts/src/client.ts) 和 [事件类型](../../ts/src/events.ts)。
101
-
102
- ### 3.4 通用签验与多签名片
103
-
104
- 应用通过 `AIDStore.sign/verify` 使用通用签验,TS/JS 两者均须 await,返回 `Promise<Result>`。默认 `format: 'raw'` 生成/验证 detached Base64 签名;`format: 'document'` 返回签后全文与签名列表,verify 返回 valid、status、payload 和逐块 signatures。先检查外层 ok,再判断验签 valid;数学失败保留全部逐块结果,resolver 操作异常是外层 error。详细参数及四语言命名见 [API 手册](06-API手册.md#通用-sign--verify)。
105
-
106
- 输入默认是文本,不猜测路径或识别 file://;读文件须显式 inputType: 'file'(Python input_type),原地签写还须 document + inPlace: true(Python in_place),成功后才写回。raw 文件按任意原字节签验,字符串和 document 严格 UTF-8;浏览器 File/Blob 只读,FileSystemFileHandle 才能原地写。verify 默认离线加载本地公钥/证书,无需私钥;历史或远端证书由应用显式提供可信 certificateResolver,不能把通用数学验签当作证书链、当前生命周期或 owner 授权检查,既有 downloadAgentMd 仍保留原远程验证流程。
107
-
108
- 需要附签时对完整已签原文使用 document + append: true;后块签正文与全部前序完整块的原始 prefix,只有已有签名链的末字节非 CR/LF 时才补 LF,无旧块按首签要求非空正文以换行结束。TAG 仅字面标签、附签有则全验;返回列表只表示实际存在的签名,不能检测末端删签。agent.md、owner.md 与公共门面复用同一内部 core,业务仍单独校验 Schema、主签身份和资源授权;普通 agent.md/owner.md 主块不输出且不接受 signer_aid。sign 本身不发布文件,名片发布仍使用 uploadAgentMd,owner.md 仍由关系 Facade 管理,见 [协议 §2.4/§2.5](../protocol/Ownership协议定义2.1.md#24-文件签名)。
109
-
110
- 新 SDK 的每个 NS GET/HEAD/PUT(含 fallback、fresh、重试)携带 X-AUN-Signature-Format: multi-v1 获取完整多签。无头旧客户端的多签读取只返回正文与首块,单签保持原 raw;HTTP 的 ETag、304 与缓存按表示区分,服务完整存储不变,应用应保留该表示原 ETag 作为条件。实体 fresh GET 还同时携带 X-AUN-Ownership-Check: 1 与 Cache-Control: no-cache,绕过 LRU 全块新鲜验证,仍为 not_applicable,不进入通用关系账本。
111
-
112
- ## 4. 七个 Facade 的参数、角色与结果
113
-
114
- 六个任务/审批方法返回 `Promise<OwnershipTaskResult>`;共识方法返回独立的 `Promise<OwnershipConsensusResult>`。方法名的 `Owneraid`、`Subaid` 大小写需按下面原样使用。
115
-
116
- | 方法及参数 | 本端调用角色 | 结果与行为 |
117
- | --- | --- | --- |
118
- | `bindOwneraid(ownerAid: string)` | sub | 请求绑定指定 owner;发起即表达 sub 意愿,owner 收到审批请求。 |
119
- | `bindSubaid(subAid: string)` | owner | 请求管理指定 sub;sub 收到审批请求。 |
120
- | `releaseSubaid(subAid: string)` | 当前/原 owner | 发布释放并等待 NS 确认;不要求 sub 审批或在线。 |
121
- | `transferSubaid(subAid: string, newOwnerAid: string)` | 当前/原 owner | 请求 sub 和新 owner 审批后转移;新 owner 必须不同于原 owner。 |
122
- | `acceptOwnershipRequest(operationId: string)` | 已验证请求的本端接收方 | 批准已有绑定或转移任务;关联原任务,不创建新任务。 |
123
- | `rejectOwnershipRequest(operationId: string, reason?: string)` | 已验证请求的本端接收方 | 拒绝已有绑定或转移任务;`reason` 是可选字符串。 |
124
- | `checkOwnershipConsensus(subAid?: string)` | 检查方 | 只读检查当前关系;省略参数时检查本端 AID,owner 查询自己管理的身份时应明确传入 sub。 |
125
-
126
- 任务结果包含 `operation_id`、`operation`(`bind`/`release`/`transfer`)、`sub_aid`、`owner_aid`、起始 `base_relation_version`、目标 `target_relation_version`、`status` 和 `step`;转移另有 `new_owner_aid`。`status` 为 `pending`、`completed`、`rejected`、`stopped` 或 `error`;`step` 是当前本端阶段字符串,不是共识枚举。`code`、`reason`、`retryable` 是可选错误信息。
127
-
128
- `pending` 可保留等待恢复的工作;`rejected`、`stopped`、`error` 会停止常规任务推进,不能假定重连后都能继续。`completed` 后仍可能为字段清理或旧文件清理发布 `ownership.error`;应用应根据任务状态和当前共识展示清理失败,不能把既成关系改回未完成。
129
-
130
- 独立绑定示例适用于已准备好的存量 sub,且没有正在续跑的 owner 注册意图。`saveBusinessTask(task: OwnershipTaskResult): Promise<void>` 由应用实现,持久保存业务记录与 SDK 任务 ID 的对应关系:
131
-
132
- ```ts
133
- import type { OwnershipTaskResult } from '@agentunion/fastaun';
134
- const task: OwnershipTaskResult = await client.bindOwneraid('owner.agentid.pub');
135
- await saveBusinessTask(task);
136
- ```
137
-
138
- 不要只保存“已点击绑定”:保存 `operation_id`、参与 AID、起始/目标版本、最后的 `status`、`step` 和错误信息,便于页面重载后继续展示同一业务任务。任务结果可带等待或错误信息,Promise 正常返回也不一定是 `completed`。类型定义见 [OwnershipTaskResult](../../ts/src/ownership-workflow.ts),包入口已公开该类型。
139
-
140
- 四个发起 Facade 会先匹配本端相同的进行中意图;匹配本端身份、发起方、操作、全部参与方及起始/目标关系版本时复用原 `operation_id`,没有匹配任务时才生成新的 UUID。应用收到 ready 消息、超时或断线后应让 SDK 恢复原任务,不能通过更改参数或伪造 `operation_id` 冒充原任务重试。
141
-
142
- 首次权威预检抛错时可能尚未创建任务,应用不一定拿到 `operation_id`;其它阶段抛错也不保证任务或副作用不存在。应用应结合已保存的业务记录、已收到的事件和当前权威关系确认阶段,不能以“没有返回 ID”为由盲目重复发起。
143
-
144
- ## 5. 审批与本地事件接入 UI
145
-
146
- 本地事件直接携带任务结果字段,并增加以下信息。它们属于本端 SDK 通知,不是服务端 `event/...`,也不作为 P2P 消息再次发送。
147
-
148
- | 载荷字段 | UI/策略用途 |
149
- | --- | --- |
150
- | `operation_id`、操作和参与 AID | 关联业务任务,展示被管理身份、原 owner、转移目标。 |
151
- | `requester_aid` | 仅 `ownership.request` 附带,经消息层确认的发起方;不能从任意聊天文本自报字段推导审批身份。 |
152
- | `local_roles` | 本端承担的 `owner`、`sub`、`new_owner` 角色数组;同一 AID 可同时承担多个角色。当前实现为各 Ownership 本地事件附带它。 |
153
- | `base_relation_version`、`target_relation_version` | 本次固定审批上下文,不允许 UI 在批准时替换目标。 |
154
- | `relation_version` | SDK 已核验目标时附带的版本;未核验时可缺省,不能用它替代新鲜共识。 |
155
- | `status`、`step`、`code?`、`reason?`、`retryable?` | 当前任务及错误展示;错误字段按实际存在处理。 |
156
-
157
- | 事件 | 应用处理 |
158
- | --- | --- |
159
- | `ownership.request` | 显示同意/拒绝或交给明确的自动策略;策略未决定时保持待审批。 |
160
- | `ownership.action_required` | 提示释放后 sub 的名片清理缺少应用明确授权;处理见第 6.2 节。 |
161
- | `ownership.progress` | 更新本端进度,不宣布关系成立。 |
162
- | `ownership.completed` | 记录本任务目标已核验;清理、副本同步和凭据交接另行跟踪。 |
163
- | `ownership.rejected` | 本次审批拒绝,不回滚已验收的历史关系。 |
164
- | `ownership.stopped` | 本次流程不再推进;不是关系解锁通知。 |
165
- | `ownership.error` | 展示错误和可重试提示,核对载荷中的任务状态;已完成关系的后续清理错误单独展示。 |
166
-
167
- `EventHandler` 是通用载荷类型,不能把回调参数直接当作一个已声明的专用请求类型。应用的 `showApproval` 应解析本端请求字段并保存 `operation_id`,再产生自己的界面决定。下面的 `appApproval` 由该 UI 或自动策略提供,类型为 `{ operation_id: string; accept: boolean; reason?: string }`;`showOwnershipError(code: string, retryable: boolean): void` 也是应用自实现函数。
168
-
169
- ```ts
170
- import { AUNError } from '@agentunion/fastaun';
171
- try {
172
- const result = appApproval.accept
173
- ? await client.acceptOwnershipRequest(appApproval.operation_id)
174
- : await client.rejectOwnershipRequest(appApproval.operation_id, appApproval.reason);
175
- await saveBusinessTask(result);
176
- } catch (error) {
177
- if (error instanceof AUNError) showOwnershipError(error.stringCode, error.retryable);
178
- else throw error;
179
- }
180
- ```
181
-
182
- 同一批准或拒绝可按原 ID 幂等处理,已经持久保存的决定不能改成相反决定。发起方无需再批准自己;审批方法只用于本端已有、已验证的绑定或转移请求。无界面应用也必须明确作出同意或拒绝,SDK 不因无人响应而默认批准。
183
-
184
- 恢复可能再次发出待审批请求。UI 按 `operation_id`、事件名和 `step` 幂等更新,已保存的决定不重新询问或改变。不要把所有历史事件都会重放当作前提:应用自己的业务记录和最后进度仍需持久保存。载荷与接线依据见 [编排指南第 2.6 节](Ownership-SDK编排指南2.1.md#26-本地事件与完成依据) 和 [当前 emit 实现](../../ts/src/ownership-workflow.ts)。
185
-
186
- ## 6. 关系操作流程
187
-
188
- ### 6.1 绑定:双方都可发起
189
-
190
- | 发起方 | 入口 | 接收方审批后的共同顺序 |
191
- | --- | --- | --- |
192
- | sub | `subClient.bindOwneraid(ownerAid)` | owner 发布自己的 `owner.md` → sub 自签提交自己的 `agent.md` → NS 验收目标 owner 与版本 → 各端新鲜核验完成。 |
193
- | owner | `ownerClient.bindSubaid(subAid)` | sub 批准后,按同一文件顺序推进。 |
194
-
195
- 绑定只从当前两份权威材料确认无锁时开始,目标版本为 `agent.md` 当前可见声明版本加一;名片无声明时基数为 `0`,目标为 `1`。已有稳定 owner 锁时,sub 不能通过普通名片更新清除或更换 owner。应用也不能因双方私下同意就跳过 NS 验收。
196
-
197
- 释放后再绑定同一 owner,若 sub 的 `agent.md` 仍保留旧声明,须先由 sub 完成已有字段清理,再发布新的 owner declare;SDK 在创建任务或产生副作用前以 `conflict`/`action_required` 提示,避免新 declare 覆盖唯一释放依据。绑定不同 owner 仍可使用当前可见版本 `v+1`;已清理时默认从 `1` 开始。
198
-
199
- ### 6.2 释放:原 owner 发起,sub 可以离线
200
-
201
- 原 owner 调用 `releaseSubaid(subAid)`,SDK 发布当前声明版本 `v` 的 release 文件;释放任务的起始、目标及历史 verified 版本均为 `v`,NS 不另存释放状态或递增版本。sub 不必在线;NS 根据 `agent.md` 的当前声明与有效 release 文件,或该 owner 路径的权威不存在结果,动态确认 `released`。服务或验证依赖不可用不能当作删除。sub 的旧名片字段可暂时保留,原 owner 可凭新鲜 `released/v`,或本任务 release 原件与当前 owner.md 全文、hash、当前有效证书精确匹配后确认的真实 `unbound/0` 完成;响应丢失时重新读取当前完整文件确认。实际完成证据保留真实状态和版本;权威删除不是取消任务。
202
-
203
- sub 收到 release 通知时,可使用本人明确 accept、含 sub 角色,且本人已签 agent 的 owner、sub 与被释放完整 statement(含 declaration_id、版本)完全匹配的原绑定/转移记录自动自签清理,即使原任务因发布响应丢失仍 pending;转移历史匹配其目标 owner。无控制消息时,仅已完成历史任务的恢复路径触发自动清理,即使没有收到 relation.confirmed,也须新鲜核验权威释放事实。清理原件及原 CAS 单独保存,历史 completed 及完成证据保持。响应丢失后复用清理原件与条件,原文、ETag及已知提交 ETag 已对应原提交时只观察完成,字段已清空时不再签名或 PUT。缺少该授权且旧字段仍在时,发布 `ownership.action_required`,本端清理任务保持等待。
204
-
205
- 释放清理不能调用 `acceptOwnershipRequest`/`rejectOwnershipRequest`,这两个接口会拒绝 release 任务。应用明确决定清理后,由 sub 用自己的身份通过现有 `AIDStore.uploadAgentMd(subAid, content)` 自签上传清除旧 `owner`、`ownership` 的名片,遵守当前 NS 条件与代际,不能指定其它上传身份或覆盖后续关系。新鲜有效名片的关系字段已清空时,SDK 仅在本任务持久清理原件、摘要、原 CAS,或本人明确 accept 的匹配原 bind/transfer.release_cleanup,与当前 NS 原文、摘要、ETag及已知提交 ETag 精确对应后观察完成;空字段本身不证明该任务完成,也不补造 sub 的清理同意或历史条件。
206
-
207
- 已完成的历史绑定/转移或释放任务保持历史完成,但当前关系必须从两份权威材料重新判断:旧声明仍在且释放依据有效时为 `released`,名片清理后为 `unbound`、版本 `0`。NS 不保留释放终局或历史版本上界,材料不可确认时不得沿用历史释放结果作当前授权。详细释放与清理规则见 [编排指南第 2.4 节](Ownership-SDK编排指南2.1.md#24-应用层-facade编排审批与共识检查) 和 [协议第 4.2 节](../protocol/Ownership协议定义2.1.md#42-解绑)。
208
-
209
- ### 6.3 三方转移
210
-
211
- 原 owner 调用 `transferSubaid(subAid, newOwnerAid)`。sub 与新 owner 分别接到同一任务的审批请求,两者可任意先后决定;全部同意后,原 owner 发布指定新 owner 的转移授权,新 owner 发布目标 `owner.md`,sub 自签提交目标 `agent.md`,NS 从旧版本 `v` 直接切换到 `v+1`。
212
-
213
- 任一尚待决定的接收方拒绝,审批阶段结束并保留原关系。批准消息本身不能完成转移;迟到拒绝不能改变同一审批方已保存的同意或已提交的关系。转移授权具有固定期限,恢复不能刷新期限或换目标,过期或版本冲突后停止旧流程。应用不得把转移失败自动改为先释放再绑定;该做法会改变授权条件和关系连续性。转移验收见 [协议第 4.3 节](../protocol/Ownership协议定义2.1.md#43-transfer_owner)。
214
-
215
- ### 6.4 自拥有与角色重合
216
-
217
- | 情形 | 本端决定与文件要求 |
218
- | --- | --- |
219
- | 建立 self-owner | sub 调用 `bindOwneraid(自己的 AID)`,或 owner 角色调用 `bindSubaid(自己的 AID)`;一次发起覆盖本端两个角色,仍分别签署、提交双文件。 |
220
- | 外部 owner → self-owner | 原外部 owner 发起转移,目标为 sub;sub 同时承担 `sub` 和 `new_owner`,一个审批决定覆盖两角色,先发布自己的 owner 文件再提交名片。 |
221
- | self-owner → 外部 owner | 同一 AID 兼任原 owner 与 sub,发起意愿覆盖这两个本端角色,外部新 owner 仍须审批。 |
222
-
223
- SDK 合并同一接收 AID 的请求,不给自己发送 P2P。self-owner 仍要验证双文件并建立锁;`human` 不能声明 owner,包括自拥有;SDK 在任务、消息和文件副作用前拒绝此绑定。原 owner 与新 owner 相同不是有效转移。业务若要求外部管理方,还须检查 `owner_aid != sub_aid`,不能仅凭 self-owner 的 `consensus` 满足该要求。参见 [协议第 4.5 节](../protocol/Ownership协议定义2.1.md#45-self-owner-的建立解绑与转移)。
224
-
225
- ## 7. 任务完成与当前共识六态
226
-
227
- 任务状态回答“这一个本端业务任务推进到哪里”,共识状态回答“当前两份权威材料证明什么关系”。普通主体适用下表六态;Group/Org 作为 `sub` 调用共识检查时返回特殊 `status/code=not_applicable`、`retryable=false`,不属于六态。P2P 投递成功、ACK、对端 `relation.confirmed` 提示或本地阶段标记都不是任务完成证据。绑定/转移的完成要求新鲜 NS 目标 owner、目标版本与本任务文件材料匹配;原 owner 必须有本任务已保存的转移授权,接收方固定首次验证授权的全文摘要及实际期限,不接受恢复时换字节或延期;释放完成要求新鲜 `released/v`,或按本任务原件严格关联的真实 `unbound/0`,任务起始、目标及历史 verified 版本仍为 `v`;历史完成记录不替代之后的当前关系查询。
228
-
229
- ```ts
230
- import type { OwnershipConsensusResult } from '@agentunion/fastaun';
231
- const consensus: OwnershipConsensusResult = await client.checkOwnershipConsensus('helper.agentid.pub');
232
- showConsensus(consensus);
233
- ```
234
-
235
- `showConsensus(result: OwnershipConsensusResult): void` 为应用自实现展示函数。结果包含 `status`、`sub_aid`、`owner_aid`(可为 null)、`relation_version`、`lock`、`agent_md_etag`、`agent_md_sha256`、`owner_md_sha256`,以及可选 `code`、`reason`、`retryable`。当 `status` 不是 `consensus` 或 `released` 时,未取得的权威观察字段可能为 null、空值或 SDK 使用的占位值(例如 `0`、`unlocked`);它们不表示实际观察到对应版本、锁或文件证据。应用必须先判断 `status`,任何结果字段本身都不能单独作为授权证据。定义见 [OwnershipConsensusResult](../../ts/src/ownership-v21.ts)。
236
-
237
- | 共识状态 | 应用含义 |
238
- | --- | --- |
239
- | `consensus` | 当前未释放关系的身份、版本和双方完整文件签名匹配;执行端仍需认证调用者并核对业务权限范围。 |
240
- | `released` | `agent.md` 仍有当前声明,但对应 `owner.md` 为有效 release 或已权威确认不存在;版本仍为该声明的 `v`,旧 owner 不再据此获权。 |
241
- | `unbound` | 新鲜有效的权威名片没有当前关系声明,版本为 `0`;释放后字段清理也属于此态。解析失败、服务不可用或不完整观察不能推断无关系,此态也不证明某个 SDK 任务已结束或对端从未准备文件。 |
242
- | `single_sided` | 仅一方准备或声明,稳定关系尚未成立。 |
243
- | `invalid` | 字段、路径、角色、版本或签名无效,不能授予 owner 权限。 |
244
- | `unavailable` | 当前 NS、Storage 或证书事实不能确认;保留最后已确认状态用于展示,不将未知当作解绑或授权。 |
245
-
246
- 公开共识方法只有 sub 参数,不能枚举全网独立 owner 声明;NS 尚无 owner 且检查器没有目标上下文时,owner 单方已准备仍可能显示 `unbound`。该边界不能被 UI 用来推断某个绑定任务已取消。
247
-
248
- 四 SDK 普通名片下载的 `verification.ownership_status` 仍是 legacy proof 展示字段,不是 2.1 授权结果。文件签名有效或旧展示状态为 complete 不能证明 2.1 共识;该展示字段对 2.1 名片显示不完整或其他旧状态也不能代替当前关系检查。应用使用 `checkOwnershipConsensus(subAid)` 获取 2.1 新鲜结果。
249
-
250
- 关系完成、sub 字段清理、旧 owner 文件条件清理、NS 向 Storage 同步名片副本、应用凭据交接应分别展示。Storage 副本尚未同步不否定 NS 已完成的验收;反过来,本地或 Storage 上的旧名片也不能覆盖当前两份权威材料的共识。
251
-
252
- 敏感业务在执行时由执行端核对当前 owner、sub、关系版本、权限范围和新鲜共识,并保存授权证据;UI 布尔值、历史完成事件和旧 token 不替代该校验。若业务使用 token/ACL,应把它们绑定到完整关系声明及其版本,并新鲜检查释放、转移后的有效性;清理后重新绑定可能再次使用版本 `1`,版本号不能单独识别关系。完整授权边界见 [协议第 6 节](../protocol/Ownership协议定义2.1.md#6-共识审计与安全边界)。
253
-
254
- ## 8. 断线与重启恢复
255
-
256
- 1. 启动时恢复原 `aunPath`、密钥解密配置、稳定设备和 slot,装载同一身份,先注册事件处理器再连接。
257
- 2. SDK 从自己的持久任务继续审批、已签文件和待发送通知;请求重发和响应丢失的恢复复用原字节与原提交条件。恢复先核对权威关系和本任务证据,旧任务不能覆盖后续代际。
258
- 3. 应用从自己的数据库恢复业务记录与 `operation_id`,幂等更新 UI。待审批请求可再次通知;已经保存的决定不重新作相反选择。
259
- 4. 已合法完成的历史任务可以保留 `completed`,即使当前关系已被后续释放或转移;当前状态另调 `checkOwnershipConsensus(subAid)` 获取。
260
-
261
- 当前七 Facade 没有公开“按 operation_id 查询任务”、取消任务或强制解锁接口。`getOwnershipStatus()`/`getOwner()` 读取旧 metadata,不是 2.1 任务查询或新鲜共识;cross-sdk 测试 agent 的私有存储查询也不是应用 API。因此业务层必须保存自己的任务关联和最后进度,不能依赖私有 `_tokenStore` 重建 UI。真实恢复触发点见 [AUNClient](../../ts/src/client.ts),任务恢复实现见 [OwnershipWorkflow](../../ts/src/ownership-workflow.ts)。
262
-
263
- 重复发起相同进行中操作会复用原 `operation_id`、审批、签名字节、提交条件和授权期限;匹配要求本端身份、发起方、操作、全部参与方及起始/目标关系版本一致。同代际不同进行中意图返回 conflict,不产生第二任务。拒绝、停止、不可重试 error 不复活;后续代际的新合法操作使用新任务,历史 completed 不仅凭参数相同复用。不要删除任务数据库、清除审批记录、删除 `owner.md` 或刷新条件来制造“恢复成功”;删除 owner 的权威文件本身可能导致释放,含义不是取消任务。
264
-
265
- Group/Org 名片失败稿及 pending 保留实体命名空间中的完整多签原文、原 CAS、固定 owner 和实体证书指纹,由应用显式重试,post-connect/重连不隐式 PUT。重试先验证完整原件及当前 owner、状态和证书代际,原条件完整且同代际原文/ETag 已确认提交时只观察完成。转移、rekey 或解散后停止旧代际待办,不更换身份、指纹或条件重签。取消实体 V2 授权后,不再保存、刷新或检查其额外授权及过期窗口;普通文件签名与当前证书检查保留。专属 create/transfer 自身 checkpoint 恢复机制不变。
266
-
267
- ## 9. 错误处理与安全降级
268
-
269
- 错误有三种入口:Facade 抛出异常;任务结果/本地事件附带错误;共识返回 `invalid` 或 `unavailable`。抛出的 `AUNError.code` 是数字 RPC 错误码,Ownership 字符串码读取 `error.stringCode`,是否可重试读取错误实例的 `error.retryable`;正常返回的任务或共识结果则读取其 `code`、`reason`、`retryable`。
270
-
271
- | 字符串码或状态 | 应用处理 |
272
- | --- | --- |
273
- | `persistence_unavailable` | 停止有副作用的编排,恢复原持久存储能力;不以新任务替代损坏的审批历史。 |
274
- | `unsupported_protocol` | 暂停 2.1 变更并核对 SDK/服务能力;不回落到 legacy 代理流程。 |
275
- | `owner_locked` | 当前关系已有锁;按当前 owner 的释放或转移流程处理。 |
276
- | `conflict` | NS ETag、owner 原件、原 NS CAS 条件、版本、目标或审批已变化;停止旧目标并重新核对权威事实,不自动换 ETag 或起始 owner 原件。 |
277
- | `forbidden` | 调用角色、身份或审批阶段不允许;不更换凭据冒用另一方。 |
278
- | `operation_not_found` | 本端没有该 ID 的请求;确认身份、持久目录及 UI 关联,不由审批 API 创建任务。 |
279
- | `invalid` | 输入、签名、证书或材料确定无效;已有任务为不可重试 error,不将验签失败当成服务不可用或同意。 |
280
- | `unavailable` | 服务、网络或依赖不可用,包括权威元数据、正文摘要不一致及 Storage Base64 传输封装损坏;已有任务保持 pending 并可重试,首次权威预检失败不创建任务。摘要匹配后确定非法的 UTF-8、文件字段或签名归 invalid。初始名片缺失或当前证书事实无法确认均须按原因处理。 |
281
-
282
- 输入格式校验也可能抛出普通 `ValidationError`,其 `stringCode` 不一定已填;不要靠字符串码穷举替代正常异常处理。`retryable` 只提示可以恢复验证,不授权换目标、刷新期限或再发起一个新的操作。服务状态未知时,普通认证和通信可按各自能力继续,依赖 owner 权限的敏感操作须暂停。
283
-
284
- 等审批、等材料及缺少 2.1 能力同样保持 pending;版本替代、目标改变、授权过期或原条件失效为 stopped;明确拒绝为 rejected,完整目标确认才为 completed。决定停止前先核验目标是否已提交;completed 后通知或清理失败只记录错误和待办。本地任务数据库写入/CAS、租约或持久化损坏返回 `persistence_unavailable`,保持原存储状态并停止副作用;远端 NS ETag、owner 原件或原 NS CAS 条件变化归为 `conflict`。三个协议时间字段采用 `1..9007199254740991` 的十进制正整数;范围内仍执行证书、当前时钟和授权未过期校验,重试不延期。
285
-
286
- ## 10. 可选托管与旧接口迁移
287
-
288
- 托管是应用显式启用的独立能力,不是绑定、释放或转移的前提。即使应用保存身份密文,两份关系文件仍由相应身份自己签署、上传。原 owner 曾能解密 sub 私钥时,关系转移不会自动撤销它掌握的凭据、续签或恢复能力;应用需独立确认凭据隔离,并将该交接进度与 NS 关系结果分开。
289
-
290
- | 旧入口/判断 | 当前接入方式 |
291
- | --- | --- |
292
- | `bindOwner(...)`/`bind_owner(...)` | sub 使用 `bindOwneraid(ownerAid)`,owner 处理本端审批。 |
293
- | `bindAid(...)`/`bind_aid(...)` | owner 使用 `bindSubaid(subAid)`,sub 明确审批。 |
294
- | `releaseOwnership(...)`/`release_ownership(...)` | 当前 owner 使用 `releaseSubaid(subAid)`。 |
295
- | 旧 `ownership_proof`、`proof.complete`、metadata owner | 改用当前双文件和新鲜 `checkOwnershipConsensus`;旧材料不是 2.1 共识证据。 |
296
- | 旧代签、代上传、默认托管或自动 rekey 流程 | 按独立身份、明确审批及应用自己的可选凭据交接接入。 |
297
-
298
- 当前这些 legacy 发起方法会抛出 `unsupported_protocol`,不是新接口的兼容别名。更换调用名称也不等于存量旧关系已经迁入 2.1;旧关系缺少可验证的当前关系事实或材料时保持原保护,迁入条件与双方重新签署需按明确方案处理,不能清空旧关系强行初始化。兼容边界见 [设计第 9 节](Ownership2.1详细设计.md#9-降级旧版及审计)。
299
-
300
- 当前实现的实际验证与限制简要查阅 [TDD 账本第 13.4 节](Ownership2.1-TDD分阶段实施计划.md#134-测试与失败续跑账本)、[第 13.6 节四 SDK 一致性检查点](Ownership2.1-TDD分阶段实施计划.md#136-四-sdk-一致性检查点) 和 [第 13.7 节复审修复验收](Ownership2.1-TDD分阶段实施计划.md#137-2026-10-11-本轮复审修复验收)。本指南的短示例按当前 TypeScript 源码核对;本地类型成立不能替代服务部署、跨端通信或真实恢复验收。
1
+ # Ownership 2.1 SDK 应用集成指南
2
+
3
+ 面向应用开发者,按“准备身份 → 发起 → 审批 → 核验 → 恢复”接入。示例使用 Node.js TypeScript SDK `@agentunion/fastaun` 当前工作区 `0.5.22`(未发布,升级基线 `0.5.21`),Node.js ≥22.16.0;实际依赖须具有本文接口。
4
+
5
+ 协议见 [Ownership 2.1](../protocol/Ownership协议定义2.1.md),SDK 内部实现见 [开发与移植指南](Ownership2.1-SDK开发与移植指南.md)。
6
+
7
+ ## 1. 应用需要理解的关系边界
8
+
9
+ | 角色/材料 | 职责 |
10
+ | --- | --- |
11
+ | sub | 被管理身份;自己签署并以本人身份向 NS 提交 `agent.md`。 |
12
+ | owner/新 owner | 自己签署并向本人 Storage 发布 `sub_aids/{sub_aid}/owner.md`。 |
13
+ | NS | 根据这两份当前权威文件核验关系;Storage 中的 sub 名片副本不参与验收。 |
14
+
15
+ owner 权限不包含 sub 私钥或代签、代上传能力。普通名片更新保留全部关系字段及原 CAS;关系无效或暂不可确认只影响依赖 owner 的授权,不阻断普通名片和通信。
16
+
17
+ 本流程用于普通主体;human 可作为 owner,不能作为声明 owner 的 sub。Group/Org 自身使用专属创建、解散和强制 rekey 转让流程:任务方法抛出 `not_applicable`,共识方法返回同名状态。它们仍可按普通 owner 规则管理其他 sub。
18
+
19
+ ## 2. 接入前提与能力检查
20
+
21
+ - 各端具有自己的私钥、有效证书和客户端;`load()` 成功后仍检查私钥。
22
+ - sub 的初始 `agent.md` 已在 NS 可读;部署具备 NS 2.1、权威 Storage、P2P 和持久任务能力。共识查询成功不代表所有发布能力可用。
23
+ - 固定可写的 `aunPath`、解密 seed、设备和 slot;任务保存在 `{aunPath}/AIDs/{aid}/aun.db`,重启沿用原数据。
24
+ - 启用 TLS 校验并配置可信根;`rootCaPath` 用于 AUN 证书验证,Node.js HTTPS 信任仍须单独正确配置。外部地址使用 `ns.{issuer}`、`st.{issuer}`。
25
+
26
+ ## 3. EC CLI 集成示例:sub 发起,human owner 同意
27
+
28
+ EC CLI 当前尚未接入 Ownership 2.1;以下是 EC/Evolcore 运行层和 owner App 后端需要接入的流程。两端各运行自己的客户端;已有客户端直接复用。
29
+
30
+ ### 3.1 EC CLI 创建 sub 身份
31
+
32
+ ```bash
33
+ ec aid new helper.agentid.pub --aun-path "<EC持久目录>" --format json
34
+ ```
35
+
36
+ 本例不指定 owner。检查 `agentmdUploaded`;未发布成功时先用现有 `ec aid agentmd put` 重试。扫码绑定和本地 `owners[]` 不代表 Ownership 共识。
37
+
38
+ ### 3.2 两端分别装载自己的身份
39
+
40
+ `config` 提供固定的 `aunPath/encryptionSeed/slotId/rootCaPath`。sub 沿用 EC 原配置(当前 seed 为 `evol`),owner 使用自己的独立存储。
41
+
42
+ ```ts
43
+ import { AIDStore, AUNClient } from '@agentunion/fastaun';
44
+ const store = new AIDStore({ ...config, verifySsl: true });
45
+ const loaded = store.load(aid);
46
+ if (!loaded.ok) throw new Error(loaded.error.message);
47
+ if (!loaded.data.aid.isPrivateKeyValid()) throw new Error('本身份私钥不可用');
48
+ const client = new AUNClient(loaded.data.aid);
49
+ ```
50
+
51
+ 两端先订阅再连接。下文 `saveMessage`、`updateView`、`saveTask` 为应用自己的消息持久处理、界面更新和业务任务保存函数。
52
+
53
+ ```ts
54
+ function watch(client: AUNClient): void {
55
+ client.on('message.received', payload => saveMessage(payload));
56
+ for (const event of ['ownership.action_required', 'ownership.progress',
57
+ 'ownership.completed', 'ownership.rejected', 'ownership.stopped', 'ownership.error']) {
58
+ client.on(event, payload => updateView(event, payload));
59
+ }
60
+ }
61
+ ```
62
+
63
+ `0.5.22` 至少需要 `message.received/message.recalled/message.batch` 中一种普通消息订阅才启动后台 P2P 拉取;已有订阅直接复用。消息处理须完成持久交付后返回,不能用空回调 ACK。仅订阅 `ownership.*` 不够;控制消息由 SDK 内部消费,仍遵守队列背压。
64
+
65
+ ### 3.3 owner App 先订阅审批,再连接
66
+
67
+ `readApproval` 从通用事件载荷中校验并提取操作、参与方、版本和 `operation_id`;`showApproval` 展示这些字段,仅在用户点击后调用回调,并处理异步错误。
68
+
69
+ ```ts
70
+ ownerClient.on('ownership.request', payload => {
71
+ const request = readApproval(payload);
72
+ showApproval(request, async accept => {
73
+ const task = accept
74
+ ? await ownerClient.acceptOwnershipRequest(request.operation_id)
75
+ : await ownerClient.rejectOwnershipRequest(request.operation_id, '用户拒绝');
76
+ await saveTask(task);
77
+ });
78
+ });
79
+ ```
80
+
81
+ ```ts
82
+ watch(ownerClient);
83
+ await ownerClient.connect({ auto_reconnect: true });
84
+ ```
85
+
86
+ 收件回调不等待用户决定;按 `operation_id` 幂等展示,不因重连重复审批或改变已保存的决定。
87
+
88
+ ### 3.4 EC/Evolcore 的 sub 发起绑定
89
+
90
+ ```ts
91
+ watch(subClient);
92
+ await subClient.connect({ auto_reconnect: true });
93
+ const task = await subClient.bindOwneraid('owner.agentid.pub');
94
+ await saveTask(task);
95
+ ```
96
+
97
+ ```mermaid
98
+ sequenceDiagram
99
+ participant S as sub SDK
100
+ participant N as sub NS
101
+ participant O as human owner App
102
+ participant T as owner Storage
103
+ S->>N: fresh 确认无锁及 Stage 能力
104
+ S->>S: 保存同意、签名原件和原 CAS
105
+ S->>N: Stage 条件提交 agent.md
106
+ N-->>S: pending / v+1 / unlocked
107
+ S->>O: 加密 bind.request
108
+ O->>O: 核验并保存请求,用户点击同意
109
+ O->>T: 本人发布匹配的 owner.md
110
+ O->>N: fresh 检查双文件
111
+ N-->>O: consensus / locked
112
+ O-->>S: 提示结果;sub 可离线后恢复
113
+ S->>N: fresh 核验目标及本人原件后完成
114
+ ```
115
+
116
+ sub 发起即表达本端同意,不再调用审批方法。Stage 只保存待确认名片,此时公共共识为 `single_sided`;owner 同意并发布后,NS 可直接验收已有候选,sub 无需再次 PUT。
117
+
118
+ ### 3.5 首次注册时携带 owner 的替代分支
119
+
120
+ ```ts
121
+ const registered = await store.register('helper.agentid.pub', {
122
+ type: 'agent', owner: 'owner.agentid.pub',
123
+ });
124
+ if (!registered.ok) throw new Error(registered.error.message);
125
+ ```
126
+
127
+ 这是显式 `bindOwneraid` 的替代入口。注册先初始化无关系名片并保存固定 ID 的意图,连接后 SDK 续跑绑定,owner 仍须审批;不要再发起另一绑定。省略 owner 只注册普通 agent;`registered: true` 不表示关系成立。
128
+
129
+ ### 3.6 通用签验与多签名片
130
+
131
+ ```ts
132
+ const signed = await store.sign(aid, text, { format: 'document' });
133
+ if (!signed.ok || !signed.data.signed) throw new Error('签名失败');
134
+ const verified = await store.verify(aid, signed.data.signed, { format: 'document' });
135
+ if (!verified.ok || !verified.data.valid) throw new Error('验签失败');
136
+ ```
137
+
138
+ 默认 `raw` 为 detached 签名;文件输入须显式 `inputType: 'file'`,附签用 `append: true`。验签检查全部已有签块,数学验签不等于当前证书或 owner 授权。签名不发布文件;完整参数见 [API 手册](06-API手册.md#通用-sign--verify)。
139
+
140
+ ## 4. 七个 Facade 的参数、角色与结果
141
+
142
+ | 方法 | 本端角色/结果 |
143
+ | --- | --- |
144
+ | `bindOwneraid(ownerAid)` | sub 发起绑定。 |
145
+ | `bindSubaid(subAid)` | owner 发起绑定,sub 审批。 |
146
+ | `releaseSubaid(subAid)` | 当前 owner 释放,不要求 sub 在线。 |
147
+ | `transferSubaid(subAid, newOwnerAid)` | 当前 owner 发起,sub 和新 owner 审批。 |
148
+ | `acceptOwnershipRequest(operationId)` | 同意本端已验证的 bind/transfer 请求。 |
149
+ | `rejectOwnershipRequest(operationId, reason?)` | 拒绝同一请求。 |
150
+ | `checkOwnershipConsensus(subAid?)` | 只读当前共识;省略参数检查本端 AID。 |
151
+
152
+ 前六项返回 `Promise<OwnershipTaskResult>`,包含 `operation_id`、参与方、base/target 版本及 `status/step`;status 为 `pending/completed/rejected/stopped/error`。共识查询返回独立的 `OwnershipConsensusResult`。
153
+
154
+ 保存业务记录与 `operation_id` 的对应关系。Promise 返回、ACK、审批通过都不是完成;`completed` 表示本端已核验本次目标,后续清理错误不撤销该结果。没有公开按 ID 查询任务、取消或强制解锁接口。
155
+
156
+ ## 5. 审批与本地事件接入 UI
157
+
158
+ | 本地事件 | 处理 |
159
+ | --- | --- |
160
+ | `ownership.request` | 展示已验证请求,等待用户或明确策略决定。 |
161
+ | `ownership.action_required` | sub 清理旧关系字段需要明确授权。 |
162
+ | `ownership.progress` | 更新阶段。 |
163
+ | `ownership.completed` | 保存本任务完成记录;当前关系另查共识。 |
164
+ | `ownership.rejected/stopped/error` | 展示拒绝、停止或错误;完成后的清理错误单独显示。 |
165
+
166
+ 载荷直接传入回调,没有 `event.data` 包装;包含任务字段及 `local_roles`,request 另含可信 `requester_aid`。按任务 ID、事件、step 幂等更新;`relation_version` 是本任务实际验收版本,不能替代当前查询。事件字段见 [编排指南 §2.6](Ownership-SDK编排指南2.1.md#26-本地事件与完成依据)。
167
+
168
+ ## 6. 关系操作流程
169
+
170
+ ### 6.1 绑定:按发起方分流
171
+
172
+ sub-first 见 §3.4;owner-first 如下:
173
+
174
+ ```ts
175
+ const task = await ownerClient.bindSubaid('helper.agentid.pub');
176
+ await saveTask(task);
177
+ ```
178
+
179
+ ```mermaid
180
+ sequenceDiagram
181
+ participant O as owner SDK
182
+ participant T as owner Storage
183
+ participant S as sub SDK
184
+ participant N as sub NS
185
+ O->>N: fresh 确认无锁
186
+ O->>T: 按原条件发布 owner.md
187
+ O->>S: bind.request
188
+ S->>S: 验证并固定提案全文/SHA,用户明确同意
189
+ S->>N: 直接条件提交 agent.md,不使用 Stage
190
+ N->>T: 核对当前声明
191
+ N-->>S: consensus / locked
192
+ S-->>O: 提示结果;owner 自行 fresh 核验完成
193
+ ```
194
+
195
+ 绑定目标版本为当前可见声明 `v+1`,无声明时从 `1` 开始。只有可靠无锁状态可发起;`invalid/unavailable` 不能当作无锁。owner-first 正常成功无需 `bind.accept/owner.ready` 往返。
196
+
197
+ 拒绝仅清理仍属于本任务、未锁定且原文/摘要/CAS 匹配的候选或邀请;不能删除已验收文件。释放后重绑同一 owner 前,先清除 sub 的旧声明,避免覆盖释放依据。
198
+
199
+ ### 6.2 释放:原 owner 发起,sub 可以离线
200
+
201
+ ```ts
202
+ const task = await ownerClient.releaseSubaid('helper.agentid.pub');
203
+ await saveTask(task);
204
+ ```
205
+
206
+ ```mermaid
207
+ flowchart LR
208
+ A[原 owner 发起] --> B[发布同版本 v 的 release]
209
+ B --> C[NS fresh 确认 released / v]
210
+ C --> D[owner 完成;sub 可离线]
211
+ D --> E[sub 回源确认释放]
212
+ E --> F{有匹配的本人历史同意吗}
213
+ F -->|有| G[本人条件清理 agent.md]
214
+ F -->|没有| H[action_required:应用明确决定清理]
215
+ H --> G
216
+ G --> I[unbound / 0]
217
+ ```
218
+
219
+ 释放不递增版本。权威确认 owner 文件不存在也可证明释放,网络错误或普通 404 不可。自动清理须匹配本人已同意的原 bind/transfer 完整声明;否则应用明确决定后,用本人 `store.uploadAgentMd(subAid, content)` 清除旧关系字段。release 不接受 accept/reject 审批。
220
+
221
+ 字段已空不能单独认领某任务完成;SDK 仍核对本任务原件和提交证据。关系释放、sub 字段清理、旧 owner 文件清理分别展示。
222
+
223
+ ### 6.3 三方转移
224
+
225
+ ```ts
226
+ const task = await ownerClient.transferSubaid('helper.agentid.pub', 'next.agentid.pub');
227
+ await saveTask(task);
228
+ ```
229
+
230
+ ```mermaid
231
+ sequenceDiagram
232
+ participant O as 原 owner
233
+ participant S as sub
234
+ participant N as 新 owner
235
+ participant NS as sub NS
236
+ O->>S: transfer.request
237
+ O->>N: transfer.request
238
+ S-->>O: 明确同意
239
+ N-->>O: 明确同意
240
+ O->>O: 发布指定目标、v+1 和固定期限的转移授权
241
+ N->>N: 验证授权,发布 v+1 owner.md
242
+ S->>NS: 本人条件提交目标 agent.md
243
+ NS-->>S: 核验三方材料,直接从 v 切到 v+1
244
+ S-->>O: 提示结果,各端自行 fresh 核验
245
+ S-->>N: 提示结果,各端自行 fresh 核验
246
+ ```
247
+
248
+ 审批未齐不发布授权;任一待审批方拒绝则停止未提交流程。授权过期不自动解除旧关系,恢复不延期、不换目标,也不改成“先释放再绑定”。
249
+
250
+ ### 6.4 自拥有与角色重合
251
+
252
+ 同一 AID 的多个角色合并为一次决定,不给自己发 P2P;双文件签署和 NS 核验仍执行。`sub.bindOwneraid(subAid)` 建立 self-owner;外部 owner 转给 sub 时,sub 同时审批 `sub/new_owner` 两个角色。human 禁止 self-owner,原 owner 与新 owner 相同不是有效转移。
253
+
254
+ ## 7. 任务完成与当前共识六态
255
+
256
+ ```ts
257
+ const current = await ownerClient.checkOwnershipConsensus('helper.agentid.pub');
258
+ if (current.status === 'consensus' && current.owner_aid === 'owner.agentid.pub') {
259
+ showBound(current);
260
+ }
261
+ ```
262
+
263
+ | status | 当前含义 |
264
+ | --- | --- |
265
+ | `consensus` | 当前双文件、签名、身份及关系版本匹配。 |
266
+ | `released` | sub 仍保留声明 v,owner 已释放;旧 owner 不再获权。 |
267
+ | `unbound` | 当前有效名片无关系声明,版本 0。 |
268
+ | `single_sided` | 单方准备或 Stage 待确认,不能授权。 |
269
+ | `invalid` | 材料确定无效,不能授权。 |
270
+ | `unavailable` | 当前事实不可确认,保留保护并等待。 |
271
+
272
+ Group/Org 的 `not_applicable` 不属于六态。先判断 status,不能把占位版本 0/unlocked 当成无锁证据。无目标上下文的查询也不能枚举独立 owner 邀请。
273
+
274
+ 普通下载的 `verification.ownership_status` 是 legacy 展示字段;当前授权使用 fresh 共识。敏感操作由执行端核对调用者、sub、owner、权限范围及完整声明;清理后可再次出现版本 1,版本号不是全局关系标识。
275
+
276
+ ## 8. 断线与重启恢复
277
+
278
+ ```mermaid
279
+ flowchart LR
280
+ A[恢复原身份、目录、设备和 slot] --> B[订阅后连接]
281
+ B --> C[SDK 读取原任务、审批、签名字节和 CAS]
282
+ C --> D{fresh 核对结果}
283
+ D -->|完整目标与本任务证据匹配| E[确认原任务完成]
284
+ D -->|尚未提交且原条件有效| F[只补未完成步骤]
285
+ D -->|依赖暂不可用| G[保留 pending]
286
+ D -->|原件或关系已变化| H[停止旧写入]
287
+ ```
288
+
289
+ `connect()` 返回不表示恢复已完成。应用恢复自己的业务任务记录并幂等更新 UI;SDK 复用原 operation,不重新绑定或转移。合法历史 completed 保留,当前关系另查。
290
+
291
+ `resetOwnershipTask()` 仅归档当前身份发起的未完成任务,不删除远端候选、不解绑或解锁;普通断线不用 reset。历史任务和三类 CAS 冲突见 [移植指南 §10](Ownership2.1-SDK开发与移植指南.md#10-持久任务审批与恢复)。
292
+
293
+ ## 9. 错误处理与安全降级
294
+
295
+ | 错误 | 处理 |
296
+ | --- | --- |
297
+ | `persistence_unavailable` | 恢复原存储,停止副作用,不删除数据库伪造新任务。 |
298
+ | `unsupported_protocol` | 核对 SDK/服务能力,不回退 legacy 写入。 |
299
+ | `owner_locked` | 由当前 owner 释放或转移。 |
300
+ | `conflict` | fresh 核对已提交目标;真实变化则停止,不换 CAS 强写。 |
301
+ | `forbidden/operation_not_found/invalid` | 检查角色、身份、任务关联或材料,不盲重试。 |
302
+ | `unavailable` | 保留原任务和字节,依赖恢复后继续核验。 |
303
+
304
+ 错误可能来自异常、任务/事件或共识结果。结果读取 `code/reason/retryable`;抛出的 `AUNError` 读取 `stringCode/retryable`,其 `code` 是数字 RPC 码。`retryable` 不授权换目标、重签或延期。
305
+
306
+ ## 10. 可选托管与旧接口迁移
307
+
308
+ 托管和凭据交接由应用独立决定;关系转移不会自动撤销旧 owner 已掌握的私钥、证书或 token。
309
+
310
+ 旧 `bindOwner/bindAid/releaseOwnership` 在新 SDK 中返回 `unsupported_protocol`;分别改用 `bindOwneraid/bindSubaid/releaseSubaid`。旧 proof、metadata owner 和旧查询不能证明 2.1 共识。新服务端保留旧 SDK 隔离兼容,新 SDK 的 2.1 操作不兼容旧服务端;不能清空旧关系强行迁入。
311
+
312
+ Group/Org 名片由实体主签、当前 owner token 上传;失败稿保留完整多签原文、固定 owner/证书代际及原 CAS,应用显式重试,重连不自动 PUT。格式见 [协议 §2.5](../protocol/Ownership协议定义2.1.md#25-grouporg-名片的实体主签与-owner-上传)。